What is the effect of 'explicit' keyword on the Return Value Optimization (RVO)?

Deadly 提交于 2019-12-11 02:07:25

问题


Following code works perfectly fine (showing 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();
}

Output:

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

If I mark the copy constructor as explicit:

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

Then the compiler errors out:

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’

Why is it happening, Shouldn't the RVO work as it is?


回答1:


RVO can elide a copy, but the language rules require that a copy (or a move) must still be possible:

[C++14: 12.8/31]: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. [..]

[C++14: 12.8/32]: [..] [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]

You made the copy impossible by adding explicit, and a move is not possible because your copy constructor blocks the creation of an implicitly-defined move constructor.

You could allow a move instead by adding your own move constructor, perhaps a defaulted one:

A(A&&) = default;

But this is only another way of abiding by the same language rule.

C++17 will relax the rule somewhat anyway, by adding some guarantees of copy elision which will not be subject to this constraint.



来源:https://stackoverflow.com/questions/38720228/what-is-the-effect-of-explicit-keyword-on-the-return-value-optimization-rvo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!