6

I was checking operator overloading in C++ and came across something I did not expect and have some doubts about it.

My copy constructor is declared and implemented as as

explicit Vector(const Vector& v);

Vector::Vector(const Vector& v) :
_x(v._x), _y(v._y), _z(v._z) {}

then I am overloading the compound assignment operators

Vector Vector::operator+(const Vector& v) const
{
    Vector tmp(*this);
    tmp += v;
    return tmp;
}

Vector Vector::operator-(const Vector& v) const
{
    Vector tmp(*this);
    tmp -= v;
    return tmp;
}

however, in the return statements I got an error saying no matching constructor for initialization of 'Vector'.

Since the only thing I added to my constructor was the explicit keyword, I deleted it and the code compiles just fine, why?

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?

explicit Vector(const Vector& v);
explicit Vector(const Vector&& v);

or just having the move constructor will work fine? If I want to stick to C++11, what is the correct approach to follow?

BRabbit27
  • 6,333
  • 17
  • 90
  • 161
  • possible duplicate of [Explicit copy constructor](http://stackoverflow.com/questions/11480545/explicit-copy-constructor) – Predelnik Apr 06 '15 at 13:54
  • More than likely `+=` and `-=` are making an implicit copy causing the error. – NathanOliver Apr 06 '15 at 13:56
  • Not an answer but a comment on your code. There is no reason to define such a copy constructor at all, as the default ones will do exactly the same. There is also usually on reason to declare a copy constructor explicit, as its putpose is to prevent implicit type conversions. – MikeMB Apr 06 '15 at 14:00
  • @MikeMB "_declare a copy constructor explicit, as its putpose is to prevent implicit type conversions_" such as? – curiousguy Jun 13 '18 at 06:12
  • 1
    @curiousguy: Sorry, badly worded: Should read "There is also usually **no** reason to declare a copy constructor explicit, as its [the explicit keyword] purpose is to prevent implicit type conversions." which is not what is happening when making a copy. – MikeMB Jun 13 '18 at 08:12

2 Answers2

5

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.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • I think I messed things up. The returned value, is it an lvalue or an rvalue? If it is an **rvalue**, couldn't I, instead of copying `tmp`, use the move constructor or move operation that is new in C++11?. If it is an **lvalue** will the function always copy the value? is there any optimization from the compiler? – BRabbit27 Apr 06 '15 at 14:43
  • 3
    @BRabbit27 the return is a rvalue, and the compiler performs the optimization whenever possible (it is called *return value optimization*, or RVO). However, if you declare the move/copy constructors `explicit`, even if the optimization is in principle possible, the compiler still complains about the `explicit` business. That's mainly because the compiler first performs correctness analysis of your program, then applies optimizations. The code should be valid C++ before the optimization phase. – vsoftco Apr 06 '15 at 14:51
  • 2
    @BRabbit27 and in C++11, the compiler first tries to move the returned object (if possible), if not, it looks for a copy constructor to copy it, and if it still doesn't find one it emits an error. That's the case here, you don't have any implicit copy/move constructors. – vsoftco Apr 06 '15 at 14:52
  • So, I guess the question to ask is: when should I use explicit in a constructor? If I just don't put the explicit keyword there my code should be fine in terms of compiling and best practices? – BRabbit27 Apr 06 '15 at 14:57
  • @BRabbit27 probably whenever you want to forbid passing by value/returning by value, and also forbid stuff like `Foo copy = original;` Say that you have some object that it should really be passed by reference, then in that case you mark the copy ctor `explicit`. – vsoftco Apr 06 '15 at 15:00
  • I still don't see why can't it copy `tmp` into the returned object due to explicit? what is the compiler trying to do (that does not work because of explicit) and what will the syntax should be in order to return a valid object? – BRabbit27 Apr 06 '15 at 15:04
  • 1
    @BRabbit27 the idea is that if you marked the copy ctor `explicit`, then the complier wants to "see" a direct invocation of it, like `Foo copy(original)`, not like `Foo copy = original`. The latter case is an implicit copy. The same happens when passing/returning to/from a function, you don't "see" the copy constructor spelled out in the code, so the copy is implicit. Because of that, `explicit` forbids it. – vsoftco Apr 06 '15 at 15:43
  • @vsoftco Where are "implicit copies" defined? – curiousguy Jun 13 '18 at 06:24
0

Returning an object by value requires that an implicit copy construction can be performed. Making the copy constructor explicit prevents that.

This is true whether or not the compiler elects not to invoke the copy constructor (e.g. the return value optimisation).

Peter
  • 35,646
  • 4
  • 32
  • 74