【问题标题】:Does Return Value Optimization need to declare a copy constructor返回值优化是否需要声明一个拷贝构造函数
【发布时间】:2015-03-04 12:57:09
【问题描述】:

我发现英特尔编译器不会为 std::array 对象生成返回值优化。以下代码恰好位于我的程序的内部循环中,并没有尽其所能进行优化。

std::array<double, 45> f(const std::array<double, 45>& y) {
    auto dy_dt = std::array<double, 45>( );
    ...

    return dy_dt;
}

我发现这种行为源于我的标准库实现没有为 std::array 显式定义复制构造函数。下面的代码证明了这一点:

class Test {
public:
    Test() = default;
    Test(const Test& x);
};

Test f() {
    auto x = Test( );

    return x;
}

当你用它编译时

icpc -c -std=c++11 -qopt-report=2 test.cpp -o test.o

报告文件显示

INLINE REPORT: (f(Test *)) [1] main.cpp(7,10)

这证明编译器生成了RVO(更改了f的签名,以便可以将新创建​​的对象放入调用站点的堆栈中)。但是如果你注释掉声明Test(const Test&amp; x);的行,报告文件就会显示

INLINE REPORT: (f()) [1] main.cpp(7,10)

证明没有生成RVO。

在定义 RVO 的 C++11 标准的 12.8.31 中,他们给出的示例有一个复制构造函数。那么,这是英特尔编译器的“错误”还是符合标准的实现?

【问题讨论】:

  • @Cyber​​ 不,如果 RVO 是可能的,它会省略副本。
  • Cyber​​:不,这里涉及到命名返回值优化。它与移动语义无关。
  • RVO 本身不需要复制构造函数,但要应用 RVO 的代码需要有效的复制或移动构造函数可用。
  • 如果你说Test(const Test&amp; x) = delete;,那么你就没有可用的、有效的复制构造函数了。
  • 我所说的几乎是重言式:RVO 无法更改某些代码是否有效,并且要按值返回对象,它必须来自可复制/可移动的类型。因此,无论 RVO 是否发生,您都需要复制/移动构造函数。

标签: c++ rvo


【解决方案1】:

由于违反了单一定义规则,该程序会导致未定义的行为,无需诊断。

在按值返回时,odr-used 复制构造函数 -- even if copy elision takes place

odr-used 的非内联函数意味着该函数的一个定义必须出现在程序中。但是您没有提供任何内容,并且您对复制构造函数的声明会抑制编译器生成的定义。

【讨论】:

  • 我认为这可能是因为没有显示所有代码。他也没有提供主线。假设,可能有另一个文件 test2.cpp,没有显示或提及,它具有该复制构造函数的定义。或者它可能在 main.cpp 中。
  • @Matt:我不明白你的意思。如果您没有定义复制构造函数,标准会为您定义一个。
  • @InsideLoop 没有;如果您不declare 复制构造函数,那么编译器会为您声明并定义一个。此外,正如 ethang 指出的那样,如果您发布了一个有效的程序(或尝试一个),这将很有用。您不能基于无法编译的程序提交优化错误报告。
  • @Matt:它确实作为一个编译单元编译,英特尔正在调查这个问题:software.intel.com/en-us/forums/topic/542477
  • Matt 的目的是提供一个完整的代码示例来展示您的问题,而不是期望其他人猜测您遗漏了什么。您在完整的程序中观察到问题可能是真的,但您还没有发布完整的程序。一般来说,发布一个小而完整的代码示例,实际展示您的问题,增加人们可以帮助您的机会。遗漏一些信息并不能帮助人们帮助你。
猜你喜欢
  • 1970-01-01
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多