Is a move constructor/assignment needed for RVO to kick in in C++11?

倖福魔咒の 提交于 2019-12-11 16:12:55

问题


For example:

In accepted answer https://stackoverflow.com/a/14623480/1423254,

Does copy elision and RVO would still work for classes without move constructors?

Yes, RVO still kicks in. Actually, the compiler is expected to pick: RVO (if possible)

In accepted answer https://stackoverflow.com/a/38043447/1423254,

Under non-guaranteed copy elision rules, this will create a temporary, then move from that temporary into the function's return value. That move operation may be elided, but T must still have an accessible move constructor even if it is never used.

The point is that I thought that RVO and "lvalue moves" (or how to call them) are 2 totally separate operations, but my colleague told me that for RVO to kick in, the class returned needs a move constructor. So I checked the internet and SO and obviously, the information can't be found quickly...


回答1:


No, if a copy constructor is accessible.

Prior to C++17 and guaranteed copy-elision, either a move constructor OR a copy constructor had to be available for the code to be legal. Elision was just an optimization, and did not affect whether the code would, or would not, compile.

That is, there is a two-steps process:

  • Evaluate whether the statement return <expr>; is legal, which prior to C++17 requires (baring conversions) that either a copy constructor or, in the presence of a temporary, a move constructor be present and accessible.
  • If possible, apply the Return Value Optimization and elide the call to said constructor.

With that in mind, let's review the quotes:

Does copy elision and RVO would still work for classes without move constructors?

Yes, RVO still kicks in. Actually, the compiler is expected to pick: RVO (if possible)

The Yes should be understood in the context of code that is legal. If the code does not compile, then the question is moot.

Under non-guaranteed copy elision rules, this will create a temporary, then move from that temporary into the function's return value. That move operation may be elided, but T must still have an accessible move constructor even if it is never used.

This is a short-cut; attempting to formulate the sentence taking into account the possible absence of a move constructor and therefore the fallback to the copy constructor would just muddy the explanation, and the OP had given no indication that there were considering such a situation.




回答2:


Short answer: no.

RVO also existed prior to C++11, when there was no such thing as a "move constructor". A copy constructor was the only requirement in that case.

The "Under non-guaranteed copy elision rules..." paragraph you quoted refers to a pre-C++17 world, where "mandatory copy elision" was not yet part of the language.

Since C++17, the following code compiles (with the guarantee of zero copies/moves):

struct foo
{
    foo() = default;
    foo(const foo&) = delete;
    foo(foo&&) = delete;
};

foo get_foo() { return foo{}; }

int main()
{
    foo f{get_foo()};
}


来源:https://stackoverflow.com/questions/56778285/is-a-move-constructor-assignment-needed-for-rvo-to-kick-in-in-c11

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