Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

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?

like image 300
Shmoopy Avatar asked Nov 02 '15 00:11

Shmoopy


People also ask

What is a Level 3 automated vehicle?

A Level 3 ready autonomous vehicle is capable of driving itself in particular conditions, during which it will take control of all safety-critical systems. In proper circumstances, the ADS (Automated Driving System) completes the entire dynamic driving task and then disengages quickly upon the driver's command.

Are there any Level 4 autonomous cars?

Having said this, it's worth pointing out that, according to J.D Power, as of May 2021, no vehicles sold in the U.S. market have a Level 3, Level 4, or Level 5 automated driving system. All of them require an alert driver sitting in the driver's seat, ready to take control at any time.

What is the distinction between Level 3 autonomy and Level 4 autonomy?

Level 3 systems cannot drive on highways, Level 4 systems can. Level 3 systems only have lateral or longitudinal control, Level 4 systems have both. Level 3 systems retire full user alertness, Level 4 systems do not​


2 Answers

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 deleted 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.

like image 118
M.M Avatar answered Oct 29 '22 12:10

M.M


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).

like image 21
Blindy Avatar answered Oct 29 '22 11:10

Blindy