Explicit Copy Constructor

Explicit copy constructor

The explicit copy constructor means that the copy constructor will not be called implicitly, which is what happens in the expression:

CustomString s = CustomString("test");

This expression literally means: create a temporary CustomString using the constructor that takes a const char*. Implicitly call the copy constructor of CustomString to copy from that temporary into s.

Now, if the code was correct (i.e. if the copy constructor was not explicit), the compiler would avoid the creation of the temporary and elide the copy by constructing s directly with the string literal. But the compiler must still check that the construction can be done and fails there.

You can call the copy constructor explicitly:

CustomString s( CustomString("test") );

But I would recommend that you avoid the temporary altogether and just create s with the const char*:

CustomString s( "test" );

Which is what the compiler would do anyway...

Explicit copy constructor behavior and practical uses

I believe the relevant sections of C++03 are §12.3.1 2:

An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor may be an explicit constructor; such a constructor will be used to perform default-initialization or value-initialization (8.5).

and § 8.5 12:

The initialization that occurs in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called copy-initialization and is equivalent to the form

    T x = a;

The initialization that occurs in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions (5.2.3), and base and member initializers (12.6.2) is called direct-initialization and is equivalent to the form

    T x(a);

Calling passByValue(a) involves copy-initialization, not direct-initialization, and thus should be an error, according to C++03 § 12.3.1 2.

Explicit keyword, move constructor and copy constructor, and disabling move and copy constructor

An explicit copy constructor works the same way as an explicit converting constructor - it cannot be invoked implicitly. The only difference is what your object is constructed from.

I would also believe that the uses cases for this are extremely rare and far between.

Slightly more common case is to have the class' copy constructor and assignment operator deleted (= delete). This is useful for objects that represent a unique resource, and therefore should not be copied. std::cout is an example of an object that exists, but should not be copied.

Explicit Copy constructor call syntax

No, they are not the same. C++ Standard section § 12.3.1 [class.conv.ctor]

An explicit constructor constructs objects just like non-explicit
constructors, but does so only where the direct-initialization syntax
(8.5) or where casts (5.2.9, 5.4) are explicitly used


Base b(a); // Direct initialization
Base b=a; // Copy initialization

Copy initialization (using =) doesn't consider explicit constructors, but direct initialization (using ()) does.

You'll have to use a cast or make your constructor non explicit if you want to use copy initialization.

Should an explicit copy constructor be ignored?

§ 12.3.1 [class.conv.ctor]/p2:

An explicit constructor constructs objects just like non-explicit constructors, but does so only where the
direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.

Example 1:

CL cl2 = 5;

§ 8.5 [dcl.init]/p17:

The function selected is called with the initializer expression as its
argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified
version of the destination type. The temporary is a prvalue. The result of the call (which is the
temporary for the constructor case) is then used to direct-initialize, according to the rules above,
the object that is the destination of the copy-initialization.

In direct-initialization, explicit constructors can be considered, so the error is not expected. GCC trunk already compiles this example successfully. This was bug 54521.


Example 2:

CL cl3 = (CL)5;

In this case, that cast syntax performs a static_cast:

§ 5.2.9 [expr.static.cast]/p4:

An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e)
if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such an
explicit conversion is the same as performing the declaration and initialization and then using the temporary
variable as the result of the conversion.

The rhs is of type CL, and the (copy-)initialization requires a non-explicit constructor, thus the error is expected.

explicit copy constructor compile error

You defined an explicit copy constructor, but the functions

Vector Vector::operator+(const Vector& v) const

and

Vector Vector::operator-(const Vector& v) const

must return by value, and cannot anymore, due to explicit (in other words, they cannot copy tmp into the returned object).

I also was checking new stuff from C++11 and occurred that I can declare my constructor like a moving-constructor
explicit Vector(const Vector&& v); and the code compiles just fine. If I do that, do I have to have both copy and move constructors?

Not sure I understand what you mean here. You will have the same issue if you only declare an explicit move constructor (which will prevent the compiler from generating a default copy constructor). I am not able to produce a "compilable" code.

Behaviour of explicit copy constructor

This:

A aa = A10x10;

Performs copy initialization. Copy initialization works by converting the object to the type of the object being initialized. However, copy initialization does this by implicit conversion. And implicit conversion cannot call an explicit constructor.

Even if it's the copy constructor.

Now by all rights, you'd think you would get a compile error. But you don't. Why? Because A is implicitly convertible by user-defined conversion to bool. And bool is convertible by standard conversion to int. And A can in fact be constructed from a single value of type int. And while implicit conversion allows only one user-defined conversion, it does allow a user-defined conversion followed by a standard conversion.

So that's what happens. It's why the first value in aa is 0 when the copy constructor is explicit.

Generally speaking, always make operator bool explicit. And never make the copy constructor explicit.

Explicit copy constructor of a parameter passed via std::async

In the post-C++20 draft (https://timsong-cpp.github.io/cppwp/n4868/futures.async) there is a "Mandates:" clause which effectively only requires std::is_move_constructible_v<A> to be satisfied. This tests whether a declaration of the form

A a(std::declval<A&&>());

would be well-formed, which it is even with explicit on the constructor. Therefore the "Mandates:"-clause is satisfied. (If it was not, the program would be ill-formed.)

However there is also a "Precondition:" clause effectively requiring A to be Cpp17MoveConstructible. This library concept has the effective requirement that

A a = rv;

where rv is a rvalue of type A (see https://timsong-cpp.github.io/cppwp/n4868/library#tab:cpp17.moveconstructible), is well-formed. This is not the case here, since this is copy-initialization which doesn't consider explicit constructors. Theferore the "Precondition:" clause is not satisfied, which causes the program to have undefined behavior.

As a result both behaviors are conforming.


However, in the current draft the precondition has been removed with resolution of LWG issue 3476 (draft commit) and I don't see anything else that would forbid the type from being usable as an argument to std::async. The arguments are now specified to be constructed with auto(/*...*/) which does consider explicit constructors. The resolution of the mentioned issue explicitly says that no other copy/move should be allowed either.

Explicit on copy constructor makes compilation error in c++. Who is responsible for casting?

It seems like you are passing the pointer bArr to a reference argument. You may want to dereference the pointer first:

*result =foo(*bArr, _b1)/goesTo;

Also I am 99% sure that is exactly what the error message states.

To answer your question. There is no implicit conversion(casting) from pointer to reference. You must explicitly use the dereference operator - prefixed*. Copy constructor is not a casting operator nor is casting operator a constructor.

Casting operator in class T converts from T to some other type. Copy constructor copies one instance of T to another instance of T. Ordinary constructor with one argument of some other type can be seen as converting said other type to an instance of type T.

EDIT: As pointed by Pete Becker this doesn't fix the problem as the explicit A(const double *arr2) is marked as explicit thus prohibiting the compiler doing the one implicit conversion that it's allowed to do.
So correct solution is to directly create A from bArr or mark it as implicit

What actually happens when copy initializing in C++?

The effect of copy initialization here is,

(emphasis mine)

If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17) prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

Note that the ojbect is direct-initialized from the converted A (from int), the copy constructor is marked as explicit or not doesn't matter here.


BTW: Since C++17 because of mandatory copy elision, the copy-construction will be elided completely.

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:



Related Topics



Leave a reply



Submit