什么是复制省略和返回值优化?

新手上路,请多包涵

什么是复制省略?什么是(命名的)返回值优化?它们意味着什么?

它们会在什么情况下发生?什么是限制?

原文由 Luchian Grigore 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 782
2 个回答

介绍

对于技术概述 - 跳到这个答案

对于发生复制省略的常见情况,请 跳至此答案

复制省略是大多数编译器实现的一种优化,用于在某些情况下防止额外的(可能是昂贵的)复制。它使按值返回或按值传递在实践中可行(有限制)。

这是省略(哈哈!)as-if 规则的唯一优化形式 - 即使复制/移动对象有副作用,也可以应用复制省略

以下示例取自 维基百科

 struct C {
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};

C f() {
  return C();
}

int main() {
  std::cout << "Hello World!\n";
  C obj = f();
}

根据编译器和设置,以下输出 都是有效 的:

你好世界!

制作了一份副本。

制作了一份副本。


你好世界!

制作了一份副本。


你好世界!

这也意味着可以创建更少的对象,因此您也不能依赖于调用特定数量的析构函数。您不应该在复制/移动构造函数或析构函数中包含关键逻辑,因为您不能依赖它们被调用。

如果省略了对复制或移动构造函数的调用,则该构造函数必须仍然存在并且必须是可访问的。这确保复制省略不允许复制通常不可复制的对象,例如因为它们具有私有或已删除的复制/移动构造函数。

C++17 :从 C++17 开始,直接返回对象时保证复制省略:

 struct C {
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};

C f() {
  return C(); //Definitely performs copy elision
}
C g() {
    C c;
    return c; //Maybe performs copy elision
}

int main() {
  std::cout << "Hello World!\n";
  C obj = f(); //Copy constructor isn't called
}

原文由 Luchian Grigore 发布,翻译遵循 CC BY-SA 4.0 许可协议

复制省略的常见形式

对于技术概述 - 跳到这个答案

对于技术含量较低的观点和介绍 - 跳到这个答案

(命名)返回值优化是复制省略的一种常见形式。它指的是从方法中通过值返回的对象的副本被删除的情况。标准中提出的示例说明了 命名返回值优化,因为对象是命名的。

 class Thing {
public:
  Thing();
  ~Thing();
  Thing(const Thing&);
};
Thing f() {
  Thing t;
  return t;
}
Thing t2 = f();

返回临时值时会发生常规 返回值优化

 class Thing {
public:
  Thing();
  ~Thing();
  Thing(const Thing&);
};
Thing f() {
  return Thing();
}
Thing t2 = f();

发生复制省略的其他常见位置是 从临时构造 对象时:

 class Thing {
public:
  Thing();
  ~Thing();
  Thing(const Thing&);
};
void foo(Thing t);

Thing t2 = Thing();
Thing t3 = Thing(Thing()); // two rounds of elision
foo(Thing()); // parameter constructed from temporary

或者当 异常被抛出并被 value 捕获时

 struct Thing{
  Thing();
  Thing(const Thing&);
};

void foo() {
  Thing c;
  throw c;
}

int main() {
  try {
    foo();
  }
  catch(Thing c) {
  }
}

复制省略的常见限制是:

  • 多个返回点
  • 条件初始化

大多数商业级编译器支持复制省略和 (N)RVO(取决于优化设置)。 C++17 强制要求上述许多复制省略类。

原文由 Luchian Grigore 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题