Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ non-static data member initializers, just a little bit confused

Tags:

c++

c++11

I am a little bit confused about why the following code does what it does:

class Base
{
public:
    Base() = default;
    Base(const Base &) =delete;
    Base &operator=(const Base &) = delete;
    Base(const char*) {}
};

class Holder
{
public:
    Holder() = default;
private:
    // Base b = Base();
    Base b2 = {};
};

int main()
{
    Holder h;
}

in this incarnation, it compiles, however if I un-comment Base b = Base(); it gives the following error:

main.cpp:15:17: error: use of deleted function 'Base::Base(const Base&)'
   Base b = Base();
                 ^
main.cpp:5:6: note: declared here
      Base(const Base &) =delete;
      ^

and I am just unable to find in the standard why it tries to call the copy constructor for the Base b = Base() initializer, and why doesn't it call for the Base b2 = {} ... or is this just one of those little obscurities that is hidden in a few words in a paragraph somewhere?

Can you please give a (short) explanation why this happens?

(coliru: http://coliru.stacked-crooked.com/a/c02ba0293eab2ce5 )

like image 483
Ferenc Deak Avatar asked Jan 19 '16 14:01

Ferenc Deak


2 Answers

That's because, conceptually, that line constructs from Base(), which requires a copy/move constructor. The probable reason why you weren't aware of this, is because that expression generally triggers copy elision: a standard optimization. It's one of those C++ gotcha's.

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

As for why Base b2 = {} works, see

(3.4) — Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

You could just do Base b;.

like image 128
Yam Marcovic Avatar answered Nov 18 '22 17:11

Yam Marcovic


T object = {arg1, arg2, ...}; is syntax for list initialization. There is no copying involved.

T object = T() is not list initialization. The right hand operand constructs a value-initialized temporary, and object is move- or copy-initialized from it. The move and copy can be elided, but the type must be movable or copyable, otherwise this is not allowed.

like image 22
eerorika Avatar answered Nov 18 '22 19:11

eerorika