C++ 这里使用的是复制构造函数、赋值运算符还是两者都使用?

C++ 这里使用的是复制构造函数、赋值运算符还是两者都使用?,c++,C++,我有一段代码: CFoo::CFoo() { InitializeCriticalSection( &m_CriticalSection ); m_IsInitialized = FALSE; m_CBar = CBar(15); } 当在CFoo构造函数第三行的右侧构造CBar实例时,是调用复制构造函数将其移动到m_CBar,还是仅由编译器调用赋值运算符?您将看到先调用构造函数CBar(15),然后会看到对赋值运算符的调用() 请注意,如果将赋值作为声明的一部

我有一段代码:

CFoo::CFoo()
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
    m_CBar = CBar(15);
}

当在CFoo构造函数第三行的右侧构造CBar实例时,是调用复制构造函数将其移动到m_CBar,还是仅由编译器调用赋值运算符?

您将看到先调用构造函数
CBar(15)
,然后会看到对赋值运算符的调用()

请注意,如果将赋值作为声明的一部分,如下所示

CBar a = CBar(15);

很可能只有构造函数,而不是构造函数+赋值()启用优化时调用,原因是。

在构造函数的成员初始值设定项列表中未显式初始化的任何类成员在输入构造函数的主体之前默认已初始化。对于类类型的成员,这意味着默认已构造:

CFoo::CFoo()
// : m_CBar()         <--------- The constructor behaves as if you wrote this*
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
    m_CBar = CBar(15);
}

*
:m_CBar()
实际值初始化
m_CBar
,这与默认初始化的作用相同,例如在这里,
m_CBar
是具有用户提供构造函数的类类型。在涉及标量类型或没有用户提供构造函数的类的情况下,值初始化将导致零初始化(随后调用任何非联合类类型的非平凡隐式默认构造函数),而默认初始化不会导致零初始化。您可以在§8.5[dcl.init]中找到所有三种初始化(零、默认和值)定义的有趣细节符合C++11标准。†


†C++14对这些规则进行了一些更改,填补了某些边缘情况下的一些漏洞。不过,最重要的更改是,具有显式默认构造函数的对象现在总是以与具有隐式定义默认构造函数的对象相同的方式处理(因此总是在调用默认构造函数(如果非平凡的话)之前初始化第一个零),不管它是否还有其他用户提供的构造函数。

将代码段分开:

CFoo::CFoo()
{
    InitializeCriticalSection( &m_CriticalSection );
m_CriticalSection
默认已初始化(即未初始化,因为它是一个没有ctor的基本类型结构)

同上,m_已初始化

    m_CBar = CBar(15);
m_CBar
默认初始化(默认ctor),然后构建临时文件,然后分配临时文件,然后销毁临时文件

}
如何减少工作量,请使用ctor初始值设定项列表:

CFoo::CFoo()
 : m_CBar(15)    // Directly constructs m_CBar, passing 15 to the CBar constructor
{
    InitializeCriticalSection( &m_CriticalSection );
    m_IsInitialized = FALSE;
}
CFoo::CFoo() : m_IsInitialized(), m_CBar(15)
{
    InitializeCriticalSection( &m_CriticalSection );
}
在C++11及更高版本中,您甚至可以将初始值设定项放入成员声明中,如果未被被调用的ctor的ctor init列表覆盖,则将使用它们

顺便说一句:在具有如下初始值设定项的定义中:

CBar a = 1;
仅调用
a
的相应ctor。
如果使用相同类型的临时文件初始化,则副本可以(并且将在任何值得使用的编译器上)省略:

或:


赋值运算符(加上用于在赋值rhs上构造临时变量的
CBar
的任何构造函数)。@T.C.,为了澄清,赋值负责“构造”McCar在某种意义上说,你知道这些临时实例周围的语义是否有C++引用?最近他们咬了我一口,我意识到我不知道这些情况下语言应该怎么做。<代码> MyCab[m_CBar不在成员初始值设定项列表中,它是在您进入构造函数主体之前默认构造的。最好使用构造函数初始值设定项列表…保存一个ctor、一个dtor和一个op=call。可能只保存一个。不保证,并且它们在任何情况下都会使用ODR。@重复数据消除或没有任何协助。可能存在副本构造复制(可能通常省略)。第二种情况取决于复制省略,并且需要存在复制构造函数。编译器可以自由地从临时构造一个临时的,移动/复制构造
a
,然后销毁临时的。不完全正确。如果
m_CBar
是一个聚合,“构造函数的行为就像…”不成立。@juanchopanza如果
m_CBar
是一个聚合,那么
CBar(15)
将不起作用。@t.C.nitpick-C++11以后,此语句不成立:“//:m_CBar()@Pradhan在这种情况下是正确的,因为
m_CBar
是一个类类型的对象,具有用户提供的构造函数。但是,你不是第一个注意到这一点的人,所以我要添加一个注释。@T.C.同意。另外,你的陈述是一个很好的说教类比,可以向这个主题相对较新的人解释这一点。然而,简练的ana逻辑有粘滞的倾向,尤其是当呈现不合格时。
CBar a = 1;
Cbar a = CBar(1);
CBar a = make_cbar(1,2,3);