如何使 Class 具有可构造的引用数据成员而无需参数?
How can I make a Class with reference data member constructible with no arguments?
我有一个 class,比如 C,其中一个成员数据,比如 X,取决于用户输入。每个 运行 的用户输入可能不同,在我当前的设计中,我的 classes 的所有实例都存储对同一对象 X 的引用。
我如何调整设计以允许不带参数的默认构造函数?
这样我就可以使用复制 assignment/copy 构造函数、创建 C 数组、使用临时右值等
以下是说明我的问题的最小工作示例。在我工作的案例中,Tag 指的是一些外部资源。
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
struct Tag {
int N;
string tag;
};
template<typename T>
struct Vec {
const Tag& tag;
T* vec;
Vec(const Tag& tag_) : tag(tag_) {
vec = new T[tag.N];
}
~Vec() {
delete [] vec;
}
};
Tag make_tag(vector<string>& args) {
assert(args.size() == 3);
int N = stoi(args[1]);
return Tag {N, args[2]};
}
vector<string> arguments(int argc, char* argv[]) {
vector<string> res;
for(int i = 0; i < argc; i++)
res.push_back(argv[i]);
return res;
}
int main(int argc, char* argv[]) {
vector<string> args = arguments(argc, argv);
Tag tag0 = make_tag(args);
Tag tag1;
Vec<double> vec(tag0);
return 0;
}
How can I tweak the design so that it allows default constructor with no arguments?
好吧,我建议三个选项:
奇特的方式:使用std::optional<std::reference_wrapper<T>>
成员。 std::reference_wrapper
is for putting reference in place where you're not sure a reference would just work as-is. std::optional<T>
持有 T
或 nullopt
(即无值)。这样做的好处是 optional
的默认初始化程序是无参数的,因此您可以为 C.
的无参数情况使用默认构造函数
老派方法:使用普通指针成员而不是引用。在无参数构造中将其初始化为 nullptr
。 (@RemyLebeau 也在评论中提出了这个建议。)
聪明的 RAII 方式:用 std::optional<C>
替换你的 class C
。这意味着无参数构造实际上并没有构造 C - 它只是保留了一个 nullopt
,延迟了以后的实际构造。当您必须在其整个存在期间保持 C
持有资源的不变性时,此解决方案是相关的;它还具有将 C
的参考成员保留为 const
.
的好处
我故意不考虑你的 MWE(你说的只是说明性的),我提供了一个更笼统的答案。
我有一个 class,比如 C,其中一个成员数据,比如 X,取决于用户输入。每个 运行 的用户输入可能不同,在我当前的设计中,我的 classes 的所有实例都存储对同一对象 X 的引用。
我如何调整设计以允许不带参数的默认构造函数?
这样我就可以使用复制 assignment/copy 构造函数、创建 C 数组、使用临时右值等
以下是说明我的问题的最小工作示例。在我工作的案例中,Tag 指的是一些外部资源。
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
struct Tag {
int N;
string tag;
};
template<typename T>
struct Vec {
const Tag& tag;
T* vec;
Vec(const Tag& tag_) : tag(tag_) {
vec = new T[tag.N];
}
~Vec() {
delete [] vec;
}
};
Tag make_tag(vector<string>& args) {
assert(args.size() == 3);
int N = stoi(args[1]);
return Tag {N, args[2]};
}
vector<string> arguments(int argc, char* argv[]) {
vector<string> res;
for(int i = 0; i < argc; i++)
res.push_back(argv[i]);
return res;
}
int main(int argc, char* argv[]) {
vector<string> args = arguments(argc, argv);
Tag tag0 = make_tag(args);
Tag tag1;
Vec<double> vec(tag0);
return 0;
}
How can I tweak the design so that it allows default constructor with no arguments?
好吧,我建议三个选项:
奇特的方式:使用
std::optional<std::reference_wrapper<T>>
成员。std::reference_wrapper
is for putting reference in place where you're not sure a reference would just work as-is.std::optional<T>
持有T
或nullopt
(即无值)。这样做的好处是optional
的默认初始化程序是无参数的,因此您可以为 C. 的无参数情况使用默认构造函数
老派方法:使用普通指针成员而不是引用。在无参数构造中将其初始化为
nullptr
。 (@RemyLebeau 也在评论中提出了这个建议。)聪明的 RAII 方式:用
std::optional<C>
替换你的 classC
。这意味着无参数构造实际上并没有构造 C - 它只是保留了一个nullopt
,延迟了以后的实际构造。当您必须在其整个存在期间保持C
持有资源的不变性时,此解决方案是相关的;它还具有将C
的参考成员保留为const
. 的好处
我故意不考虑你的 MWE(你说的只是说明性的),我提供了一个更笼统的答案。