首页 > 解决方案 > c++03中的复制省略

问题描述

在某些情况下,复制省略在 c++17 中是强制性的,而在 c++11/14 中是允许的。这尤其涉及复制初始化。例如下面的程序

#include <iostream>

struct A
{
  explicit A(int){ std::cout << "conversion" << std::endl; }
  A(const A&) { std::cout << "copy constructor" << std::endl; }
};

int main()
{
    A b = A(3);
}

预计在 c++17 中会产生输出

conversion

并且在 c++11/14 中可能会产生相同的输出。考虑到这些方面,gcc 10.1.0 和 clang 11.1.0 也使用-std=c++11or生成上面的输出-std=c++14,除非使用 明确禁用可选的构造函数省略-fno-elide-constructors

但是c++03标准呢?是否允许在复制初始化中省略复制构造函数?gcc 和 clang-std=c++03总是禁止复制构造函数(除非指定-fno-elide-constructors)。

标签: c++language-lawyerc++03copy-elision

解决方案


是的,C++03 和 C++98 中允许复制省略。这是 C++98 和 C++03 的段落:

复制操作的非强制性省略

在以下情况下,允许编译器,但不要求忽略类对象的复制构造,即使复制构造函数和析构函数具有可观察到的副作用。对象直接构建到存储中,否则它们将被复制到其中。这是一个优化:即使它发生并且没有调用复制构造函数,它仍然必须存在并且可以访问(好像根本没有发生优化),否则程序是错误的:

  • 在 return 语句中,当操作数是具有自动存储持续时间的非易失性对象的名称时,它不是函数参数或 catch 子句参数,并且属于相同的类类型(忽略 cv 限定)函数返回类型。这种复制省略的变体被称为 NRVO,“命名返回值优化”。

  • 在对象的初始化中,当源对象是无名临时对象并且与目标对象具有相同的类类型(忽略 cv-qualification)时。当无名临时变量是 return 语句的操作数时,这种复制省略的变体称为 RVO,“返回值优化”。

当复制省略发生时,实现将省略复制操作的源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象被销毁的较晚时间没有优化

参考

我删除了自 C++11 起才有效的所有内容。

C++98、C++03 和 C++11 关于省略的唯一区别是移动操作和异常处理。


推荐阅读