不可预测的复制省略?

Unpredictable copy elision?

根据这个Wiki page代码如下:

#include <iostream>

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

C f() {
  return C();
}

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

可能会产生不同的输出,具体取决于编译器和编译器的设置。

如果我无法预测程序的行为方式(我无法真正知道具有任何给定设置的任何给定版本中的任何给定编译器会或不会优化掉哪些内容),我该如何编写程序?是否有任何我应该遵循的关于复制省略的一般准则?

编写不依赖于是否存在复制省略的代码。

主要是尊重rule of 3/5/0.

在这里,您的 class C 的主要目的是展示复制省略。

在常规情况下,class 包含数据和/或管理资源。 那么应该实现正确的 copy/move 构造函数来保持不变,避免双重删除,...

因此删除副本只是一种优化。

还有其他结构可能依赖于 compiler/build/run:

  • Order of evaluation of function argument 未指定。您应该编写不依赖于该评估顺序的代码。

    template <typename ... Ts> void any_order_call(Ts&&...){}
    
    std::ostream& hello() { return std::cout << "hello "; }
    std::ostream& world() { return std::cout << "world"; }
    
    void maybe_hello_world()
    {
        any_order_call(world(), hello());
    }
    

    所以输出可能是

    hello world
    

    worldhello 
    
  • sizeof(int) 取决于 compiler/architecture,你不应该假设它的大小。 对于这个,您可能已经测试了那个 (if (sizeof (int) == 4)) 或(可选 :( ) 固定大小类型 (std::int32_t, ...).

  • ...