Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What changes to C++ made copy initialization work for class with explicit constructor?

Consider this code:

struct X{
    explicit X(){}
    explicit X(const X&){}
};

void foo(X a = X()){}

int main(){}

Using C++14 standard, both GCC 7.1 and clang 4.0 rejects the code, which is what I expected.

However, using C++17 (-std=c++1z), they both accept the code. What rule changed?


For both compilers to exhibit this same behavior, I doubt this to be a bug. But as far as I can tell, the latest draft still says, default argument uses the semantics of copy-initialization 1. Again, we know that explicit constructors will only allow direct initialization 2.

1: dcl.fct.default/5; 2: class.conv.ctor/2

like image 442
WhiZTiM Avatar asked May 24 '17 09:05

WhiZTiM


People also ask

How constructor solve the problem of initialization?

The constructors should be used to initialize member variables of the class because member variables cannot be declared or defined in a single statement. Therefore, constructors are used in initializing data members of a class when an object is created.

What is a copy constructor a constructor to initialize an object with the values of another object?

What is a Copy Constructor in C++? Copy constructors are the member functions of a class that initialize the data members of the class using another object of the same class. It copies the values of the data variables of one object of a class to the data members of another object of the same class.

What will happen if a copy constructor?

An implicitly defined copy constructor will copy the bases and members of an object in the same order that a constructor would initialize the bases and members of the object.

Which constructor is used for initialising an object through another object?

A copy constructor is a member function that initializes an object using another object of the same class.


1 Answers

Because the behavior of copy elision changes from C++17; for this case copy elision is mandatory.

Mandatory elision of copy/move operations

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

  • In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

    T f() {
        return T();
    }
    
    T x = T(T(f())); // only one call to default constructor of T, to initialize x
    

Note: the rule above does not specify an optimization: C++17 core language specification of prvalues and temporaries is fundamentally different from that of the earlier C++ revisions: there is no longer a temporary to copy/move from. Another way to describe C++17 mechanics is "unmaterialized value passing": prvalues are returned and used without ever materializing a temporary.

And for copy initialization:

The effects of copy initialization are:

  • First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather that a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)

  • If T is a class type and the cv-unqualified version of the type of other is T or a class derived from T, the non-explicit constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.

That means for X a = X(), a will be default constructed directly, the copy/move constructors and their side effects will be omiited completely. The selection of non-explicit constructors for overload resolution won't take place, which is required in C++14 (and before). For these guaranteed cases, the copy/move constructors don't participate in, then it won't matter whether they're explicit or not.

like image 118
songyuanyao Avatar answered Oct 07 '22 16:10

songyuanyao