不可预测的复制省略?

问题描述

根据此 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

在这里,您的类 10.0 9.0 0.09999999999999995 0.9 8.0 False 的主要目的是展示复制省略。

通常情况下,类包含数据和/或管理资源。 那么应该实现正确的复制/移动构造函数以保持不变,避免双重删除,...

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

还有其他可能依赖于编译器/构建/运行的构造:

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

    C

    所以输出可能是

    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)) 或(可选的 :( )固定大小类型 (if (sizeof (int) == 4),...)。

  • ...