C++字符串初始化

6
我看到一份声明,根据该声明
string noun("ants");
string noun = "ants";

两者完全等价。

这与我的直觉相反:我认为在第二种情况下发生了一次转换(通过string类的构造函数),然后使用string类的参数调用赋值运算符。实际上是什么情况?


7
C++正在发生,这就是事实。在这两种情况下都进行了初始化,因此不会调用op=函数。与string noun; noun = "ants";进行比较。 - Bartek Banachewicz
2
俗话说得好:“初始化不等于赋值”。 - pmr
没有任何赋值,但两者仍然不完全等价;请参考Joachim Pileborg的答案。 - James Kanze
这就是为什么你应该在你的类中添加一个拷贝构造函数。有些人添加了一个赋值运算符,却想知道为什么它从未被调用。 - clambake
1
@clambake 或者禁止复制和赋值操作。(对于多态类型,这是我经常做的事情。) - James Kanze
2个回答

9

对于使用赋值进行变量定义的初始化,例如

std::string a = "foo";

在这里创建了两个对象:您定义的变量(在我的示例中为a)和一个临时对象(用于字符串"foo")。然后使用临时对象调用变量a的复制构造函数,然后销毁临时对象。不会调用复制赋值运算符。
但是,如果编译器使用复制省略,则可以避免复制,这是一种避免不必要的复制和复制的优化技术。即使不调用复制构造函数,复制构造函数仍然需要存在。

对于定义

std::string a("foo");

有一种更好的构造函数,它接受指向常量字符串的指针,而字面值"foo"可以被视为常量数组char(实际上,字符串字面值是常量字符数组,但与所有数组一样,它们会衰减为指针)。


同意,“复制构造函数”在两种情况下都会被调用。 - Subhajit
1
这不是发生的事情。没有创建两个对象。 - Michael
@Michael 从概念上讲,是的。标准包含特殊语言,允许编译器省略额外的对象,即使它不能证明复制构造函数只是复制,大多数实现也是如此。 - James Kanze
@Michael,尝试删除复制构造函数或将其设置为“private”,然后你的编译器应该会在第二个版本中报错。 - M.M

3
我觉得这可能比较难找到,但是还是来试一试:
§12.6.1 明确初始化([class.expl.init])
complex a(1);   // initialize by a call of
                // complex(double)
complex b = a;  // initialize by a copy of a

正如@pmr所指出的那样,初始化不是赋值,因此不会调用赋值运算符。有关详细信息,请参阅其余的12.6.1

有价值的信息也可以在§8.5 ([dcl.init])中找到,其中8.5.1表示

initializer:
    brace-or-equal-initializer
    ( expression-list )
brace-or-equal-initializer:
    = initializer-clause
    braced-init-list

以下是关于初始化的示例,包括8.5.2

免责声明:我只有n3485版本的文档,但我认为C++14版本并没有改变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接