【问题标题】:Unpredictable copy elision?不可预测的复制省略?
【发布时间】:2021-03-29 10:43:02
【问题描述】:

根据这个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();
}

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

如果我无法预测程序的行为方式,我该如何编写程序?是否有我应该遵循的有关复制省略的一般准则?

【问题讨论】:

  • 尊重 3/5/0 规则,不依赖于复制省略存在/不存在。
  • 请注意,您的示例在 C++17 中是可预测的,没有副本。
  • 您能否解释一下如果复制省略完成或未完成,您的程序会出现什么问题?
  • 构造函数不应该有任何必要的副作用(例如std::cout来表明调用了特定的构造函数),因为这些副作用不能保证会发生。构造函数是特殊的,编译器可以相当积极地优化它们。
  • 一个有用的指导方针是编写代码,这样无论是否省略副本都无关紧要。 (如果出现这种情况,这通常是设计问题的征兆。)

标签: c++ copy-elision


【解决方案1】:

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

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

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

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

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

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

  • 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) 取决于编译器/架构,您不应假设它的大小。 对于这个,您可能需要测试 (if (sizeof (int) == 4)) 或 (optional :( ) 固定大小类型 (std::int32_t, ...)。

  • ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多