【问题标题】:Copy Constructor/Assignment Operator复制构造函数/赋值运算符
【发布时间】:2014-10-07 20:39:59
【问题描述】:

我正在学习 Accelerated C++ 中的自动转换,作者指出,当您有表单的语句时,总是会调用复制构造函数

myClass myVar = 24;

另外,他说当你有表格的陈述时

myClass myVar;
myVar = 24;

实际发生的是调用以整数作为参数的 myClass 构造函数来创建类型为 myClass 的未命名临时变量,然后调用赋值运算符。我相信这本书写于 2000 年。我的问题是这些说法是否仍然正确。我在其他地方了解了移动构造函数和移动赋值操作,我想知道是否调用了它们而不是赋值运算符/复制构造函数。

感谢您的宝贵时间。对此,我真的非常感激。

【问题讨论】:

  • 不看类定义是不可能的。
  • 如果myClass 有一个移动构造函数和一个移动赋值运算符,那么它们将被使用
  • @MattMcNabb 我看到移动赋值运算符肯定可以发挥作用(第二个 sn-p),但我看不到移动-构造函数会出现在哪里要么 sn-p。你会在哪里看到它?对于 OP,作者在这些评估中的任何一个都不再必然准确。
  • @WhozCraig:首先,一个临时的myClass(24) 将用于复制/移动初始化myVar,除非复制/移动被省略。

标签: c++ copy-constructor accelerated-c++


【解决方案1】:

...作者指出,当您有表单的语句时,始终会调用复制构造函数

myClass myVar = 24;

错误

您的书是在 C++11 成为新标准之前编写的,因此它没有提到移动语义以及可能调用 move-constructor 的可能性。此外,它没有谈到复制省略。是的,确实可以调用被调用的复制构造函数,但是由于称为复制elison 的优化,允许编译器从复制/移动构造函数中删除调用。这是允许的,即使它可能会影响程序的行为,但请注意,这保证每个编译器都会发生。

如果您编写program 来测试此行为,您会发现没有调用复制/移动构造函数。传递命令行参数 -fno-elide-constructors disables 这个省略号并允许来自 move-constructor 的调用。

您使用的初始化形式称为复制初始化

§ 8.5/15 初始化器

表单中发生的初始化

T x = a;

以及在 参数传递、函数返回、抛出异常 (15.1)、 处理异常(15.3)和聚合成员初始化 (8.5.1) 称为复制初始化。 [ 注意:复制初始化可能 调用移动 (12.8)。 ——尾注]

假设没有发生复制省略,编译器将构造一个类的临时实例,以便转换为指定的类型。然后它将使用复制构造函数或移动构造函数从这个临时对象中复制或移动构造myVar。移动构造函数优先于右值的复制构造函数,并且仅当您的类具有可访问的移动构造函数时才会调用;否则调用复制构造函数。

如果没有发生复制省略,编译器将初始化myVar,就好像它是从右侧复制构造的一样。这与as-if rule 一致,其中指出编译器可以执行优化,因为它不会影响程序的可观察行为

另外,他说当你有表格的陈述时

myClass myVar;
myVar = 24;

实际发生的是myClass 调用以整数作为参数的构造函数来创建 myClass 类型的未命名临时变量,然后是 赋值运算符被调用。 [...] 我的问题是这些说法是否仍然正确。

是的,构造函数确实参与了隐式类型转换。来自最新草稿,N3797

§ 12.3 转换

类对象的类型转换可以由构造函数和 通过转换函数。这些转换称为用户定义的 转换 并用于隐式类型转换(第 4 条),用于 初始化 (8.5) 和显式类型转换 (5.4, 5.2.9)

你的作者对那部分的解释是正确的,除了 move-assignment 操作符 如果它是可访问的就会被调用。

【讨论】:

  • 感谢您提供清晰、详细的回答。我相信这是你第二次为我解决了很多困惑。享受你的一周。
  • AC++ 是一本广受好评的书,我怀疑实际文本(OP 转述)将允许复制省略
猜你喜欢
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 2013-04-13
  • 2014-10-12
  • 1970-01-01
相关资源
最近更新 更多