简体   繁体   中英

What's the difference between auto a = A(3) and A a(3)?

Suppose I have:

struct A
{
    A(int x) : m_x(x) { }
    A(A&&) = delete;
    int m_x;
}

and:

A a(3); // Ok
auto a = A(3); // Error: function A(int&&) cannot be referenced - it's a deleted function

Why does the latter call to the move constructor? Why are these 2 statement different in terms of generated code?

auto a = A(3); means the same as A a = A(3); since the type of the right hand side is A .

This means exactly what it looks like: A(3) creates a temporary A initialized with 3 , and then A a = _____ means: create an A called a with _____ as initializer.

So you create a temporary, pass that to a as initializer, and then the temporary is destroyed. This type of initialization (with = ) is called copy-initialization (although don't confuse that with "copy", it's just a word).

A constructor is selected to construct a which accepts an A . This must be either a copy or a move constructor. A has a move constructor and a copy constructor. The latter is implicitly-generated and defined as deleted too, because there is a user-declared move constructor.

Being defined as deleted doesn't affect overload resolution though; and the move-constructor is preferred to the copy-constructor in this case.

So your code attempts to call a delete d function, which is ill-formed, hence the error.

Note that if the move-constructor were not deleted, then copy elision would apply. It kicks in in some circumstances where a variable is initialized from a temporary, or a local variable is returned by value. The rule is that the compiler may use the same memory for both a and the temporary object, and omit the call to the copy/move constructor.

Most/all compilers would actually do this in the circumstance. So you can actually write auto a = A(3); and in practice not get any unnecessary moves. If you write some code for your move-constructor that outputs something, you will hopefully find that nothing is output.

If you want to make absolutely sure there is no unnecessary copy, or construct an object that has no usable copy nor move constructor - stop writing code that specifies unnecessary copies! A a(3); is sufficient.

Why would you expect both code paths to be the same?

You're obviously constructing an unnamed object in the second example, allocating a ( auto a ) and then copying from the temporary to a (which is a move because we're talking about a temporary object).

It doesn't matter that compiler will generate the same code in both cases, because at compile time the necessary functions/constructors are needed to be defined. Think of it this way - optimization will occur after compilation/code-parsing, but in the end code willbe(should-be) the same in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM