C++类:是否可以在构造函数主体中选择成员的构造函数?(无需双重初始化成员)
C++ classes: Is it possible to select a member's constructor in a constructor body? (Without doubly initializing the member)
考虑一下:
class Foo {
private:
Bar x;
public:
Foo(int a) { // no initialization here since constructor is dependent on a following if-block
if (a==0) x=Bar(12,'a', 34); // some (int, char, int) constructor of Bar
else x=Bar(13); // (int) constructor of Bar
}
}
这应该做的是检查参数 a 的值,并根据 a 的值使用某个构造函数和某些参数初始化柱 x。然而,问题是,这当然被编译器读取为
Foo(int a): Bar() { // !
if (a==0) x=Bar(12,'a', 34); // some Bar(int, char, int) constructor of Bar
else x=Bar(13); // Bar(int) constructor of Bar
}
编译器将 Bar() 添加到初始化列表中,因为我省略了它。它现在被双重初始化,一次使用其 () 构造函数,一次在函数体中。但是,如果初始化 Bar(即使使用其默认构造函数)非常昂贵(关于性能)并且我不能或不想要这种双重初始化怎么办?
我怎么能不初始化 x 柱线,直到在实际的构造函数主体中?如果不可能,我将如何最好地解决此问题?
补充一点:为什么C++以这种方式设计?为什么它会在实际构造函数体之前强制初始化成员?
我认为你问错了问题,而不是试图禁止初始化,你应该这样做,即将你的ctor拼写为:
Foo(int a) : x((a==0) ? Bar(12,'a', 34) : Bar(13)) {}
这不会导致任何复制或移动(见这里),并且是惯用的。
不,你不能。成员保证在 ctor 正文中时被初始化。
整个初始化顺序明确定义为:
- 首先,派生最多的类的构造函数调用虚拟基类子对象的构造函数。虚拟基类按深度优先、从左到右的顺序进行初始化。
- 接下来,直接基类子对象按照它们在类定义中声明的顺序构造。
- 接下来,(非静态)成员子对象按其顺序构造在类定义中声明。
- 最后,执行构造函数的主体。
您可以将x
设为std::unique_ptr<Bar>
,然后在 ctor 中根据需要分配它。
C++是这样设计的,以便构造函数实际构造和初始化事物,而不是让你搬起石头砸自己的脚。
尽管如此,从C++11开始,现在可以使用一种后门脚射击技术:匿名工会的成员不会被构建,除非你明确构建它们。代码将是:
class Foo
{
union
{
Bar x;
};
public:
Foo(int a)
{
if (a==0)
new(&x) Bar(12,'a', 34);
else
new(&x) Bar(13);
}
~Foo()
{
x.~Bar();
}
};
需要明确的是,这确实应该是最后的手段。编译器生成的复制构造函数、移动构造函数等被定义为已删除,因此如果您希望这些操作可用,您也需要实现它们。
内存方面比匿名联合解决方案略贵,但更不容易出错,并且不会产生额外的复制/移动或动态分配。
class Foo {
private:
std::experimental::optional<Bar> x;
public:
Foo(int a) {
if (a==0) x.emplace(12,'a', 34); // some (int, char, int) constructor of Bar
else x.emplace(13); // (int) constructor of Bar
}
};
此外,在这种情况下,x
将用作指针:x->some_Bar_function()
和some_function_taking_a_Bar(*x)
。
下面是使用委托构造函数的解决方案:
class Foo
{
Bar b;
Foo( Bar b ): b(std::move(b)) { }
public:
Foo(int a): Foo( a ? Bar(13) : Bar(12, 'a', 34) ) {}
};
在委派期间创建所需的对象,然后调用采用Bar
的构造函数。 如果你想允许任何人从酒吧构造一个Foo,那么你可以公开这个构造函数。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 继承:构造函数,初始化C++11中基类的类C数组成员
- C++-我可以创建另一个类的成员并在构造函数中使用它吗
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- constexpr构造函数需要常量成员函数时出现问题
- 如何在c++中定义以struct为数据成员的类中的构造函数
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- std::ofstream 作为类成员删除复制构造函数?
- c++构造函数成员初始化:传递参数
- C++初始化类实例时隐式调用类成员的构造函数
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 在构造函数中输入对象时C++类成员作用域
- 解释了构造函数成员初始化列表
- 构造函数成员初始值设定项跨成员列出,安全吗?
- C 构造函数成员分配优化
- 类内/构造函数成员初始化
- 在构造函数成员初始化之前调用成员函数的语法
- 非构造函数成员函数中的显式字符串行为