什么是具有复制和直接初始化行为不同背后的动机是什么?什么是具有复制和直接初始化行为不同背后的动机是什

2019-06-14 06:25发布

有些涉及到为什么叫而不是转换构造拷贝构造函数?

有两种语法进行初始化,指示按和复制初始化:

A a(b);
A a = b;

我想知道有不同定义的行为他们的动机。 对于拷贝初始化,一个额外的拷贝参与进来,我想不出任何目的执行复制。 因为它是从一个临时的副本,它可以并且可能会被优化掉了,因此用户不能依靠它发生 - ERGO的额外副本本身不是足够的理由不同的行为。 所以为什么?

Answer 1:

只有炒作,但恐怕这将是很难做到没有了Bjarne Stroustrup的确认它到底是如何更肯定的:

它被设计这种方式,因为它假定这种行为将被程序员可以预料的,他会期待当=使用标志进行拷贝,而不是与直接初始化语法来完成。

我觉得可能复制省略只在标准的后续版本中加入,但我不知道 - 这是一些人可能能够通过检查标准的历史肯定的告诉。



Answer 2:

因为它是从一个临时的副本,它可以并且可能会被优化掉

这里的关键词是可能 。 该标准允许,但不要求,编译器优化复制了。 如果一些编译器允许这个代码(优化),但其他人拒绝了(非优化的),这将是很不一致。

因此,标准规定处理这种一致的方式 - 每个人都必须检查的拷贝构造函数是可访问的,他们是否然后使用与否。

这个想法是,所有的编译器要么接受代码或拒绝。 否则,这将是不可移植。


另一个例子,考虑

A a;
B b;

A a1 = a;
A a2 = b;

这将是同样不一致,使a2但禁止a1A复制构造函数是私有的。


我们也可以从初始化类对象的两个方法分别旨在是不同的标准文本见(8.5 / 16):

如果初始化直接初始化,或者如果它是复制初始化其中源型的CV-不合格的版本是同一类或派生类中,阶级目的地,构造被考虑。 适用的构造列举(13.3.1.3),和最好的一个是通过重载解析(13.3)选择的。 如此选择的构造函数被调用来初始化对象,与初始化表达式或表达式列表作为其参数(一个或多个)。 如果没有构造适用,或重载决议是模糊的,是形成不良的初始化。

否则(即,对于剩余的复制初始化例),其是如在13.3描述列举了可以从源类型转换为目标类型或(当使用的转换函数)来派生类用户定义的转换序列。 1.4,最好的一个是通过重载解析(13.3)选择的。 如果转换无法完成,或者是模糊的,是形成不良的初始化。 选择时调用初始化表达式作为其参数的功能; 如果函数是一个构造函数,调用初始化一个临时的目标类型的CV-不合格的版本。 临时是prvalue。 该调用的结果(这是临时的构造的情况下)随后被用于直接初始化,根据上述的规则,即复制初始化的目的地的对象。 在某些情况下,一种实施方式是允许的,以消除通过直接构建中间结果到对象被初始化这直接初始化所固有的复制; 见12.2,12.8。

的差别在于,所述直接初始化直接使用所构建的类的构造函数。 与复制初始化,其他转换功能被认为是与这些可产生临时具有被复制。



Answer 3:

看看下面的例子:

struct X
{
    X(int);
    X(const X&);
};

int foo(X x){/*Do stuff*/ return 1; }
X x(1);
foo(x);

在我测试的编译器,该参数foo总是复制甚至全部优化开启。 从这一点,我们可以收集该副本不会/不能在所有情况下消除。

现在,让我们觉得从语言设计的角度来看,所有的想象,你会去想,如果你想使规则时,需要一个副本,当它不是场景。 这将是非常困难的。 此外,即使你能拿出的规则,他们会非常复杂,几乎不可能为人们理解。 然而,在同一时间,如果你被迫到处复制,那将是非常低效的。 这就是为什么规则是现在这个样子,你让规则理解为人们同时还不会强迫,如果能够避免它们被制作的复制品理解。

我现在得承认,这个答案是非常相似的苏马的答案。 这个想法是,你可以期望与当前规则的行为,以及其他任何会太辛苦的人跟随。



Answer 4:

内置的类型,如初始化:

int i = 2;

很自然的语法,部分原因是由于历史的原因(还记得你高中数学)。 它比更自然:

int i(2);

即使一些数学家可能会说这一点。 毕竟,没有什么在调用一个函数(在这种情况下,一个构造函数),并传递一个参数不自然。

对于内置类型这两种类型的初始化是相同的。 有前外壳没有多余的副本。 这对于具有两种类型的初始化和原来没有具体打算使之表现不同的原因。

不过,也有用户定义类型和语言的既定目标之一是让他们表现为内置类型尽可能接近。

因此,复制结构(以输入从一些转换功能,例如)是天然执行所述第一语法的。

你可能有额外的副本,他们可能被省略的事实是用户定义类型的优化。 无论复制省略和显式的构造来得很晚到语言。 这并不奇怪,标准允许使用一定时期后的优化。 此外,现在你可以消除过载分辨率候选明确的构造函数。



文章来源: What's the motivation behind having copy and direct initialization behave differently?