拷贝删节法

copy elision method

本文关键字:拷贝      更新时间:2023-10-16

来自标准定义的复制省略方法:

在c++计算机编程中,拷贝省略指的是一种编译器优化技术,它可以消除不必要的对象复制。

让我们考虑下面的代码:

#include <cstdlib>
#include <iostream>
using namespace std;
int n=0;
struct C 
{
 C (int) {}
 C(const C&) {++n;}      

       };
int main(int argc, char *argv[])
{
    C c1(42);
    C c2=42;


return n;
}

这行"return n"将返回0或1,取决于是否省略了副本。

还考虑以下代码:

#include <iostream>
struct C {
  C() {}
  C(const C&) { std::cout << "Hello World!n"; }
};
void f() {
  C c;
  throw c; // copying the named object c into the exception object.
}          // It is unclear whether this copy may be elided.
int main() {
  try {
    f();
  }
  catch(C c) { 
}
}

上面说

// copying the exception object into the temporary in the exception declaration.
//It is also unclear whether this copy may be elided.

所以我的问题是实现这种优化方法有多有用,如果有时结果是未定义的?一般来说,它使用的频率是多少?

重要的一点是标准明确地允许这样做,这意味着您不能假设复制构造函数的副作用将被执行,因为副本可能被省略。该标准要求复制构造函数的实现具有复制构造函数语义,也就是说,其总体目的是在您的域中生成与原始对象语义等效的第二个对象。如果您的程序符合这一点,那么优化将不会影响程序。

这是真的,另一方面,这是我能想到的唯一一种情况,在这种情况下,标准允许根据编译器的工作从同一个程序中获得不同的可见结果,但是你已经被建议在你的复制构造函数中不应该有副作用(或者更确切地说,你不能依赖于执行的副本的确切数量)。

至于是否值得,是的。在许多情况下,复制是相当昂贵的(我故意忽略了讨论中的c++ 11中的move-constructors)。考虑一个返回vector<int>的函数,如果副本没有被省略,则需要另一个动态分配,复制所有向量内容,然后释放原始内存块这三个操作都可能是昂贵的。

或者,您可以强制用户更改他们的代码以创建一个空对象并通过引用传递它,但这会使代码更难阅读。