【问题标题】:What is the effect of 'explicit' keyword on the Return Value Optimization (RVO)?'explicit' 关键字对返回值优化 (RVO) 有何影响?
【发布时间】:2016-08-02 12:18:10
【问题描述】:

以下代码运行良好(显示 RVO):

struct A { 
  A (int) { cout << "A::A()\n"; }  // constructor
  A (const A&) { cout << "A::A(const A&)\n"; }  // copy constructor
};

A foo () { return A(0); }

int main () {
  A a = foo();
}

输出:

A::A()  // --> which means copy constructor is not called

如果我将复制构造函数标记为explicit

explicit A (const A&) { ... }

然后编译器报错:

explicit.cpp: In function ‘A foo()’:
explicit.cpp:10:22: error: no matching function for call to ‘A::A(A)’
 A foo () { return A(0); }
                      ^
explicit.cpp:5:3: note: candidate: A::A(int)
   A (int) { cout << "A::A()\n"; }
   ^
explicit.cpp:5:3: note:   no known conversion for argument 1 from ‘A’ to ‘int’
explicit.cpp: In function ‘int main()’:
explicit.cpp:14:13: error: no matching function for call to ‘A::A(A)’
   A a = foo();
             ^
explicit.cpp:5:3: note: candidate: A::A(int)
   A (int) { cout << "A::A()\n"; }
   ^
explicit.cpp:5:3: note:   no known conversion for argument 1 from ‘A’ to ‘int’

为什么会这样,RVO 不应该按原样工作吗?

【问题讨论】:

  • 这与 RVO 无关。
  • 看起来像这样回答它:stackoverflow.com/questions/29472565/…
  • @KonradRudolph,但是没有explicit 关键字,RVO 正在发生,并且不会制作A 的多个副本。当我们将构造函数标记为explicit 时,为什么不应该继续进行相同的操作? Q 可能与 RVO 没有直接关系,但我发现两者之间存在一些间接联系。 @NathanOliver,感谢您指出。那个 Q 显示了观察结果。然而,这个问题是关于“为什么?”
  • 这在答案下方的评论中得到了回答。我想这并不能真正使它成为一个骗局,但嗯。

标签: c++ compiler-errors copy-constructor explicit return-value-optimization


【解决方案1】:

RVO 可以省略复制,但语言规则要求复制(或移动)必须仍然可以:

[C++14: 12.8/31]: 当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数有副作用. [..]

[C++14: 12.8/32]: [..] [ 注意:无论是否会发生复制省略,都必须执行此两阶段重载解决方案。它确定如果不执行省略则要调用的构造函数,并且即使调用被省略,所选构造函数也必须是可访问的。 ——尾注]

您通过添加explicit 使复制变得不可能,并且无法进行移动,因为您的复制构造函数阻止了隐式定义的移动构造函数的创建。

您可以通过添加自己的移动构造函数来允许移动,也许是默认构造函数:

A(A&&) = default;

但这只是遵守同一语言规则的另一种方式。

无论如何,C++17 都会通过添加一些不受此约束的复制省略保证来稍微放宽规则。

【讨论】:

  • (出于此答案的目的,忽略移动语义,因为问题中的代码显然没有。)
猜你喜欢
  • 2011-11-27
  • 1970-01-01
  • 2013-10-16
  • 2021-04-04
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-04
相关资源
最近更新 更多