C++ 初始化:括号与等号

C++ 初始化:括号与等号,c++,initialization,C++,Initialization,两者之间有什么区别 T a(b); 及 及 ?除非=运算符重载,否则=运算符将调用默认的复制构造函数我相信。。。这将是一个肤浅的副本;将相同的成员值指定给第一个对象作为右侧操作符 T a(b); 调用接受b的a构造函数。(如果b的类型相同,则调用复制构造函数) 创建类型为T的临时对象,由b构造。然后调用复制构造函数(=在本例和下一例中都不是赋值!) 同上!除了我们显式构造了一个临时对象 请注意,该标准允许在第二种和第三种情况下完全消除临时副本。此外,如果b不是T类型,则在第一种情况下T不必具

两者之间有什么区别

T a(b);


除非=运算符重载,否则=运算符将调用默认的复制构造函数我相信。。。这将是一个肤浅的副本;将相同的成员值指定给第一个对象作为右侧操作符

T a(b);
调用接受
b
a
构造函数。(如果
b
的类型相同,则调用复制构造函数)

创建类型为
T
的临时对象,由
b
构造。然后调用复制构造函数(
=
在本例和下一例中都不是赋值!)

同上!除了我们显式构造了一个临时对象


请注意,该标准允许在第二种和第三种情况下完全消除临时副本。此外,如果
b
不是
T
类型,则在第一种情况下
T
不必具有复制构造函数。在第二和第三种情况下,即使实现可以自由地优化整个过程,它仍然需要一个可访问的副本构造函数。IIRC标准调用这个:复制省略。

它们都是构造函数调用,=符号只是语法上的糖。具体调用哪些构造函数在一定程度上取决于编译器

T a( b );
是直接初始化,除非它解析为函数声明,在这种情况下,它是函数声明

T a = b;
是复制初始化,这意味着它的工作方式就像在右侧构造临时对象一样,然后从该临时对象复制构造
a
,或者在C++11及更高版本中,可能从该临时对象移动构造

编译器可以随时删除(删除)临时+复制/移动,但复制或移动构造函数(无论在逻辑上使用哪个构造函数)必须仍然是可访问的,而不是显式的

例如,在C++03中,无法复制并初始化
std::ostringstream
,因为它没有复制构造函数。在C++11中,如果初始值设定项是临时的,则可以复制并初始化一个
ostringstream
,这将导致逻辑移动构造(但通常会被省略、优化)。例如,此副本初始化声明

ostringstream s = ostringstream( "blah" );
int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
…不作为C++03编译,因为在C++03中,复制初始化调用类的复制构造函数,该构造函数不存在。但是,它编译为C++11,因为在C++11中,复制初始化调用移动构造函数。虽然(为了保持其流的假象)std::ostringstream不能直接复制,但它可以移动

另一个区别是:在C++03中,只有复制初始化语法支持大括号初始值设定项,在C++03中,当
T
是聚合类型(如原始数组)时,可以使用大括号初始值设定项。在C++11中,大括号符号作为一种统一的初始化语法进行了扩展和推广,因此它也可以用于直接初始化。下面的直接初始化声明

ostringstream s = ostringstream( "blah" );
int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
…不作为C++03编译,但作为C++11及更高版本编译

=
复制初始化语法是C中的原始初始化语法


在C++11及更高版本中,由于移动语义,它可以在比C++03更广泛的情况下使用,例如使用
std::ostringstream

Nope。发布的代码中没有赋值运算符。第二种和第三种情况之间的实际区别是,在第三种情况下,允许显式使用相关的非复制构造函数(如果使用,则取决于
b
)。第二种情况并非如此。我不确定这是否就是你所说的“除了我们显式地构造了一个临时对象”的意思,说得好。也许我应该像你指出的那样澄清一下,第二个在
显式
构造函数的情况下不起作用
假设
b
的类型没有命中任何接受
b
类型的构造函数,但是
b
的类型中存在一些转换运算符,那么就考虑转换了?Fredwolf指出,当
b
的类型为
t
时,编译器不仅可以省略临时+复制,它必须这样做。但仍然需要一个可访问的副本构造函数。还有一个区别,因为拷贝初始化需要一个可访问的拷贝构造函数,它不是显式的。我知道这是一个老问题,但是你提到的,在右边的
ta=b
temporary是从
b
构造的,那么
a
是从这个临时构造的拷贝。。。。我做了测试,我用所有类型的构造函数创建了一个类,当调用
ta=b
时,它只执行一个副本构造。。。那么我在这里遗漏了什么呢?@Laith:好吧,你在读到的句子中遗漏了“好像”,在下一句中遗漏了“编译器可以随时删除临时+复制”。;-)请注意,即使复制构造函数有副作用,编译器也可以省略复制构造。本质上,编译器可以盲目地假设复制构造函数进行复制,而不做任何其他事情,不管明显的现实情况如何。另外,自从2010年写下这个答案以来,我们已经有了C++11,它通过引入移动语义改变了一切。一个C++复制初始化可以移动或复制,根据。谢谢,这清除了我的困惑,谢谢你带来这个老答案我的注意。我现在已经更新了它。希望不会带来任何重大错误。:)不,调用哪个构造函数是由标准精确定义的。编译器在这方面没有发言权。它所能影响的只是是否调用已定义的构造函数,即它是否在任何特定情况下执行复制/移动省略,在这种情况下,天真的非优化编译器将执行冗余
ostringstream s = ostringstream( "blah" );
int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };