为什么在不涉及副本的情况下std :: string s =“ 123”被认为是副本初始化?

时间:2020-06-04 03:15:51

标签: c++

为什么用这种方式初始化std :: string: std::string s = "123"; 被认为是副本初始化,什么时候实际上没有任何副本发生?

在上述情况下,毫无疑问,编译器将看到有一个std::string的{​​{1}}构造函数,因此这里发生的是char const *的构造通过将std::string隐式转换为char const *来实现对象。这是一个明确的场景。它只是简单地调用std::string构造函数一次。如此简单,关于复制优化和移动之类的优化甚至没有什么可谈论的。

现在,问题是,我从未对通过隐式转换(即,类a =表达式)进行对象初始化感到任何困惑,直到我开始接触文献宣称=的初始化是“复制初始化”。甚至主要人物Bjarne Stroustrup本人也将这种初始化形式称为“复制初始化”。

在这一点上,我觉得我可能误会了一些东西。

那么,为什么如果允许隐式转换显然不是这种情况,为什么将by by初始化为=复制初始化?

2 个答案:

答案 0 :(得分:3)

术语copy-initialization仅用于以下形式的初始化语法:

T object = other;

此初始化的影响之一是:

如果T是类类型,而other类型的cv不合格版本不是T或不是从T派生的,或者T是非类类型,但是other的类型是类类型,则用户-检查可以从其他类型转换为T的定义的转换序列(如果T是类类型并且可以使用转换函数,则转换为从T派生的类型),并通过重载分辨率选择最佳转换序列。

对于表达式:

std::string s = "123"; 

采用const char *的隐式constructor用于构造std::string

因此,即使其中包含术语 copy ,复制初始化也不意味着涉及实际的 copy ,它之所以被称为是因为语法使之成为现实出现就像正在复制一样。

答案 1 :(得分:2)

之所以称其为复制初始化,是因为在C ++ 11之前,按照语言规则,这实际上是必须要做的。当你有

T t = u;

如果uT,则调用副本构造函数。因此,在这种情况下,将其称为复制初始化是有道理的

如果u不是T,则[dcl.init] / 15项目符号7开始起作用(from the C++03 draft),并且已经

否则,将枚举可以从源类型转换为目标类型或(当使用转换功能时)转换为其派生类的用户定义转换序列(即,对于其余的复制初始化情况)在13.3.1.4中,最好的方法是通过过载分辨率(13.3)选择。如果转换无法完成或模棱两可,则初始化格式错误。所选函数以初始化器表达式作为参数进行调用; 如果函数是构造函数,则调用将初始化目标类型的cv不合格版本的临时类。临时是右值。然后,根据上面的规则,调用的结果(对于构造方法来说是临时的)用于直接初始化作为复制初始化目标的对象。通过将中间结果直接构造到要初始化的对象中,允许实现消除此直接初始化中固有的复制;参见12.2、12.8。

强调我的

指出创建了一个临时对象,该临时对象用于初始化它们。是的,它说在某些情况下可以避免这种情况,但是这些部分仅允许进行优化,没有强制性的要求。

所以,我们再次制作一个副本,所以复制初始化很有意义。

对于C ++ 17,情况已不再如此,您可以保证不存在任何副本,但此时仍保留名称。

相关问题