【问题标题】:Is copy/move elision allowed when returning *&object?返回 *&object 时是否允许复制/移动省略?
【发布时间】:2017-08-08 06:52:36
【问题描述】:

看看这段代码:

#include <stdio.h>

struct Foo {
    Foo() { }
    Foo(const Foo &) { printf("copy\n"); }
    Foo(Foo &&) { printf("move\n"); }
};

Foo getFoo() {
    Foo f;
    return *&f;
}

int main() {
    getFoo();
}

C++14 标准规定 (12.8/31) 允许复制/移动省略:

在具有类返回类型的函数的返回语句中,当 表达式是非易失性自动对象的名称(除了 一个函数或 catch 子句参数)具有相同的 cv-unqualified type 作为函数返回类型,可以进行复制/移动操作 通过将自动对象直接构造到 函数的返回值

在我的示例中,返回表达式不是名称,因此我认为不允许省略。

我检查了 GCC/clang/MSVC,虽然 clang/MSVC 没有忽略副本,但 GCC 可以。 GCC在这里违反标准吗?

【问题讨论】:

  • 好吧,我不明白为什么编译器会保留多余的 *&amp; 运算符。另外,您使用的是哪个版本的编译器?你是在 C++14 模式下构建的吗?另外,在引用标准时,请注明代码出处(名称或章节/章节编号)。
  • 在一个完全不相关的注释上,你为什么使用printf 输出?为什么不std::cout
  • @Someprogrammerdude - 编译器可能不会将它们保留在发出的代码中。但它们确实会影响标准观点的表达式的语义。这根本不是 id 表达式(或名称)。
  • 在您引用的部分之后不久,标准说:当尚未绑定到引用的临时类对象将被复制/移动到具有相同 cv-unqualified 的类对象时类型,可以通过将临时对象直接构造到省略的复制/移动的目标中来省略复制/移动操作这个规则,结合你引用的那个,允许return *&amp;f;的复制省略。跨度>
  • @pschill: f in getFoo 不是临时对象。

标签: c++ language-lawyer


【解决方案1】:

首先,“as-if”规则在这里不适用,因为您的复制和移动构造函数有副作用(它们执行 IO)。因此 GCC 不能省略该标题下的复制/移动。

乍一看,我看不到任何其他允许省略的措辞,所以我认为这是 GCC 中的一个错误。另一方面,我非常希望标准扩大复制/移动省略的范围以包括这种情况。 (在您提供的最小示例中,我看不出它会如何导致问题 - 我想您有一个很大的示例。)

【讨论】:

  • 允许编译器省略复制/移动,即使在这种情况下它们有副作用。
  • @Zereges 当允许复制/移动省略时,即使编译器有副作用(在标准定义的正式意义上),它也是允许的。我的第一段的要点是,如果构造函数没有副作用,即使在 12.8/31(根据“as-if”规则)not 允许省略,也可以省略它们。 12.8/31 不适用于“在这种情况下”,“as-if”不适用于“在这种情况下”=> 省略是一个错误。
  • @Zereges 我是否需要扩展我的答案以包含上述一些评论?
猜你喜欢
  • 2021-02-08
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
相关资源
最近更新 更多