Move Constructor vs Copy Elision. Which one gets called?

我的未来我决定 提交于 2019-11-28 10:25:20

In the comments of another SO answer, the OP clarifies what he is asking here:

I heard that copy elision CAN occur even when there are more than 1 return statements. I'd like to know when a copy elision is forbidden

And so I am attempting to address this issue here:

Elision of copy/move operations (referred to as copy elision by the C++ standard) is permitted in the following circumstances:

  • In a return statement in a function with a class return type, when the expression is the name of anon-volatile object with automatic storage duration (other than a function parameter or a variable introduced by the exception-declaration of a handler) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value.

  • In a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object can be omitted by constructing the automatic object directly into the exception object.

  • When a temporary class object that has not been bound to a reference would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move.

  • When the exception-declaration of an exception handler declares an object of the same type (except for cv-qualification) as the exception object, the copy operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration. There cannot be a move from the exception object because it is always an lvalue.

Copy elision is forbidden in all other circumstances.

The number of return statements in a function has no bearing whatsoever on the legality of copy elision. However a compiler is permitted to not perform copy elision, even though it is legal, for any reason at all, including the number of return statements.

C++17 Update

There are now a few places where copy elision is mandatory. If a prvalue can be bound directly to a by-value function parameter, or a by-value return type, or to a named local variable, copy elision is mandatory in C++17. This means that the compiler shall not bother even checking for a copy or move constructor. Legal C++17:

struct X
{
    X() = default;
    X(const X&) = delete;
    X& operator=(const X&) = delete;
};

X
foo(X)
{
    return X{};
}

int
main()
{
    X x = foo(X{});
}

The copy elision is an optimization that, nowadays, every modern compiler provides.

When returning huge class objects in C++, this technique applies... but not in every case!

In the first example, the compiler performs the Move Constructor because we have more than one return statement in the function.

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