Che*_*Alf 28

T a( b );
Run Code Online (Sandbox Code Playgroud)

直接初始化,除非它作为函数声明解析,在这种情况下它是一个函数声明.

T a = b;
Run Code Online (Sandbox Code Playgroud)

复制初始化,这意味着它就好像在右侧构造一个临时对象,a然后复制构造,或者在C++ 11及更高版本中,可能从该临时构造移动构造.

只要有可能,编译器就可以自由地删除(删除)临时+复制/移动,但是复制或移动构造函数(无论哪个逻辑上使用)必须仍然可以访问而不是explicit.

例如,在C++ 03中,您无法复制初始化a std::ostringstream,因为它没有复制构造函数.在C++ 11中,ostringstream如果初始化程序是临时的,则可以复制初始化,然后导致逻辑移动构造(但通常会被省略,优化掉).例如,这个复制初始化声明,

ostringstream s = ostringstream( "blah" );
Run Code Online (Sandbox Code Playgroud)

...不编译为C++ 03,因为在C++ 03中,复制初始化调用类的复制构造函数,该构造函数不存在.然而,它确实编译为C++ 11,因为在C++ 11中,复制初始化调用移动构造函数.虽然(为了保持其作为流的假象)std::ostringstream不能直接复制,但它可以被移动.

另一个这样的区别:在C++ 03中,只有复制初始化语法支持花括号初始化程序,在C++ 03中你可以使用何时T是聚合类型,如原始数组.在C++ 11中,花括号表示法已经扩展并概括为统一初始化语法,因此它也可以用于直接初始化.所以下面的直接初始化声明,

int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
Run Code Online (Sandbox Code Playgroud)

...不编译为C++ 03,但编译为C++ 11及更高版本.

=副本初始化语法与C的原始初始化语法

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


Ara*_*raK 19

T a(b);
Run Code Online (Sandbox Code Playgroud)

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

T a = b;
Run Code Online (Sandbox Code Playgroud)

T创建一个类型的临时对象来构造b.然后调用复制构造函数(=在这种情况下不是赋值,下一个案例!).

T a = T(b);
Run Code Online (Sandbox Code Playgroud)

和上面一样!除了我们显式构造一个临时对象.

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

  • 第二种和第三种情况之间的实际区别在于,在第三种情况下,允许相关的非复制构造函数(如果使用,取决于"b"的类型)是显式的.在第二种情况下,它不是.不确定这是否是你所说的"除了我们明确地构建了一个临时对象",或者不是. (3认同)
  • 第一行中的拼写错误:“T a(b);”调用“T”的构造函数,而不是“a”。 (2认同)

归档时间:

查看次数:

20648 次

最近记录:

9 年,3 月 前