复制和直接初始化的动机背后的动机是什么?

Luc*_*ore 43 c++ history language-design initialization

为什么调用复制构造函数而不是转换构造函数有点相关

初始化,直接和复制初始化有两种语法:

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

我想知道他们有不同定义行为的动机.对于复制初始化,涉及额外的副本,我不能想到该副本的任何目的.由于它是来自临时文件的副本,它可以并且可能会被优化,因此用户不能依赖它发生 - 因为额外的副本本身不足以应对不同的行为.所以为什么?

Bo *_*son 4

由于它是临时文件的副本,因此它可以而且可能会被优化掉

这里的关键词可能是。该标准允许但不要求编译器优化副本。如果某些编译器允许此代码(已优化),但其他编译器拒绝它(未优化),则这将非常不一致。

因此,标准规定了处理此问题的一致方法 - 每个人都必须检查复制构造函数是否可访问,无论他们是否使用它。

这个想法是所有编译器都应该接受代码或拒绝它。否则它将是不可移植的。


另一个例子,考虑

A a;
B b;

A a1 = a;
A a2 = b;
Run Code Online (Sandbox Code Playgroud)

当复制构造函数是私有的时,允许a2但禁止同样会不一致。a1A


我们还可以从标准文本中看到,初始化类对象的两种方法本来是不同的(8.5/16):

如果初始化是直接初始化,或者是复制初始化,其中源类型的 cv 未限定版本与目标类是同一类或目标类的派生类,则考虑构造函数。枚举适用的构造函数(13.3.1.3),并通过重载决议选择最好的构造函数(13.3)。调用如此选择的构造函数来初始化对象,并使用初始化表达式或表达式列表作为其参数。如果没有应用构造函数,或者重载决策不明确,则初始化格式错误。

否则(即,对于其余的复制初始化情况),可以如 13.3 中所述枚举可以从源类型转换为目标类型或(当使用转换函数时)转换为其派生类的用户定义的转换序列。 1.4,并通过重载决议(13.3)选择最好的一个。如果转换无法完成或不明确,则初始化格式错误。使用初始值设定项表达式作为其参数来调用所选函数;如果该函数是构造函数,则调用会初始化目标类型的 cv 未限定版本的临时版本。临时值是纯右值。然后,根据上述规则,调用的结果(对于构造函数情况来说是临时的)用于直接初始化作为复制初始化目标的对象。在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除直接初始化中固有的复制;见12.2、12.8。

不同之处在于直接初始化直接使用构造类的构造函数。通过复制初始化,会考虑其他转换函数,这些函数可能会产生必须复制的临时值。

  • 这回答了这个问题:“为什么即使应用复制省略,复制构造函数也需要可访问?”。它没有回答这个问题:“为什么定义复制初始化语法来执行可以省略的复制?” (4认同)
  • @RedX - 不,编译器被明确允许消除复制*即使*如果有副作用。 (2认同)