为什么用这种方式初始化std :: string:
std::string s = "123";
被认为是副本初始化,什么时候实际上没有任何副本发生?
在上述情况下,毫无疑问,编译器将看到有一个std::string
的{{1}}构造函数,因此这里发生的是char const *
的构造通过将std::string
隐式转换为char const *
来实现对象。这是一个明确的场景。它只是简单地调用std::string
构造函数一次。如此简单,关于复制优化和移动之类的优化甚至没有什么可谈论的。
现在,问题是,我从未对通过隐式转换(即,类a =表达式)进行对象初始化感到任何困惑,直到我开始接触文献宣称=的初始化是“复制初始化”。甚至主要人物Bjarne Stroustrup本人也将这种初始化形式称为“复制初始化”。
在这一点上,我觉得我可能误会了一些东西。
那么,为什么如果允许隐式转换显然不是这种情况,为什么将by by初始化为=复制初始化?
答案 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;
如果u
是T
,则调用副本构造函数。因此,在这种情况下,将其称为复制初始化是有道理的
如果u
不是T
,则[dcl.init] / 15项目符号7开始起作用(from the C++03 draft),并且已经
否则,将枚举可以从源类型转换为目标类型或(当使用转换功能时)转换为其派生类的用户定义转换序列(即,对于其余的复制初始化情况)在13.3.1.4中,最好的方法是通过过载分辨率(13.3)选择。如果转换无法完成或模棱两可,则初始化格式错误。所选函数以初始化器表达式作为参数进行调用; 如果函数是构造函数,则调用将初始化目标类型的cv不合格版本的临时类。临时是右值。然后,根据上面的规则,调用的结果(对于构造方法来说是临时的)用于直接初始化作为复制初始化目标的对象。通过将中间结果直接构造到要初始化的对象中,允许实现消除此直接初始化中固有的复制;参见12.2、12.8。
强调我的
指出创建了一个临时对象,该临时对象用于初始化它们。是的,它说在某些情况下可以避免这种情况,但是这些部分仅允许进行优化,没有强制性的要求。
所以,我们再次制作一个副本,所以复制初始化很有意义。
对于C ++ 17,情况已不再如此,您可以保证不存在任何副本,但此时仍保留名称。