在构造函数代码之前禁用默认 class 成员初始化
Disable default class member initialization before constructor code
在 C++ 中,在成员初始化列表中 而非 构造的任何 class 成员默认在包含 class 的构造函数之前构造被执行。但是,如果该成员变量只是要在 位于 的 class 的构造函数中构造,这似乎是非常浪费的。
我在下面提供了一个示例来阐明我的意思。这里,Example
class有一个LargeIntimidatingClass
类型的成员变量x
。使用成员初始化列表(Example
中的第一个构造函数)x
只构造一次。但是,如果x
不能用成员初始化列表合理构造,就会构造两次!
//This class used as part of the example class further below
class LargeIntimidatingClass {
// ...
//many member variables and functions
// ...
LargeIntimidatingClass() {
//Painfully expensive default initializer
}
LargeIntimidatingClass(int a, double b) {
//Complicated calculations involving a and b
}
};
//Here, this class has a LargeIntimidatingClass as a member variable.
class Example {
LargeIntimidatingClass x;
char c;
//Basic member initialization list constructor. Efficient!
Example(int a, double b, char c) : x(a,b), c(c) {}
//What if the parameters to the LargeIntimidatingClass's constructor
//need to be computed inside the Example's constructor beforehand?
Example(std::string sophisticatedArgument) {
//Oh no! x has already been default initialized (unnecessarily!)
int a = something1(sophisticatedArgument);
double b = something2(sophisticatedArgument);
//x gets constructed again! Previous (default) x is totally wasted!
x = LargeIntimidatingClass(a,b);
c = something3(sophisticatedArgument);
}
};
是的,我知道在这个愚蠢的例子中你可以写 Example(string s) : x(f1(s),f2(s)), c(f3(s)) {}
,但我相信你可以想象将一堆逻辑推入成员初始化列表的情况很麻烦(甚至不可能) ).
当成员变量没有在成员初始化列表中列出时,是否可以禁用成员变量的默认构造函数?
Is it possible to disable a member variable's default constructor when it is not listed in the member initialization list?
不,那不可能。
禁用语言的一个组成部分是如何工作的?不,但是您可以重构 使用 语言,或者以各种方式绕过它。
- 有一个指向扩展 class 的(智能)指针成员。
- 让成员成为
std:aligned_storage
并通过 placement new 创建对象。然后自己小心管理对象的生命周期。 - 抱一个
std:optional
。管理初始化并让库类型管理其余的对象大小开销。
您不能禁用构造。在到达构造函数的主体之前,必须初始化所有 class 成员。也就是说,您可以轻松解决该问题。您可以添加一个私有静态成员函数,从中获取 a
和 b
和 returns 一个 LargeIntimidatingClass
,例如
class Example {
LargeIntimidatingClass x;
char c;
static LargeIntimidatingClass make_LargeIntimidatingClass(std::string sophisticatedArgument)
{
int a = something1(sophisticatedArgument);
double b = something2(sophisticatedArgument);
return LargeIntimidatingClass(a,b);
}
static char make_c(std::string sophisticatedArgument)
{
return something3(sophisticatedArgument);
}
public:
//Basic member initialization list constructor. Efficient!
Example(int a, double b, char c) : x(a,b), c(c) {}
// now we use helpers to initialize in the member initialization list
Example(std::string sophisticatedArgument) : x(make_LargeIntimidatingClass(sophisticatedArgument), c(make_c(sophisticatedArgument) {
//now everything is initialized correctly
}
};