If I have a Point class, the copy constructor should look like this:
Point(const Point &p);
Point(Point &p);
However, what if I want to create a constructor, which requires a Point? Why is it considered as copy constructor, instead of a constructor?
Point(const Point p)
Compiler error: "copy constructor for class "Point" may not have a parameter of type "Point"
You can not have a copy constructor signature to accept the argument by value. The reason is simple - in order to pass parameter by value, you need to invoke copy constructor, which will require to pass parameter by value, and will invoke copy constructor... Welcome to endless recursion.
Compiler is saving you a lot of trouble by not allowing this construct.
Point(const Point p)
Why is it considered as copy constructor, instead of a constructor?
It's not.
As the standard says in §12.8/2:
A non-template constructor for class X is a copy constructor if its
first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other
parameters have default arguments (...).
In fact, your declaration is ill-formed. §12.8/6 says:
A declaration of a constructor for a class X is ill-formed if its
first parameter is of type (optionally cv-qualified) X and either
there are no other parameters or else all other parameters have
default arguments.
You do have exactly that: a constructor for a class Point whose first parameter is of type const Point and there are no other arguments.
This is of course the formal explanation. As others have explained, the practical implication of such a constructor would be infinite recursion.
Perhaps you are concerned about the error message you got. However, there are absolutely no rules regarding the contents of a diagnostic message produced by a compiler. It's a quality-of-implementation issue; if your compiler thinks that copy constructor for class "Point" may not have a parameter of type "Point" is a good way to convey the problem to its users, then so be it.
Related
Does the && and in the parameters mean that this is a move constructor?
Vertex(int&& val, float&& dis)
: value_(std::move(val)), distance_(std::move(dis)),
known_(false), previous_in_path_(nullptr)
{}
Do all move constructors have to have a parameter that is an object of the same class as the constructor is in? Like this?
Vertex(Vertex&& rhs)
: value_(std::move(rhs.value_)), distance_(std::move(rhs.distance_)),
known_(false), previous_in_path_(nullptr)
{}
I just need clarification as to what is and what isn't a move constructor.
From the Move constructors documentation:
A move constructor of class T is a non-template constructor whose
first parameter is T&&, const T&&, volatile T&&, or const volatile
T&&, and either there are no other parameters, or the rest of the
parameters all have default values.
(emphasis is mine)
This means that in order to be a move constructor, the first parameter must be a rvalue reference (potentially const/volatile) to the same type.
You can add additional parameters, but they must have default values.
Therefore your 1st constructor is not a move constructor, but the 2nd one is.
Consider the following program and the comments in it:
template<class T>
struct S_ {
S_() = default;
// The template version does not forbid the compiler
// to generate the move constructor implicitly
template<class U> S_(const S_<U>&) = delete;
// If I make the "real" copy constructor
// user-defined (by deleting it), then the move
// constructor is NOT implicitly generated
// S_(const S_&) = delete;
};
using S = S_<int>;
int main() {
S s;
S x{static_cast<S&&>(s)};
}
The question is: why does not user-defining the template constructor (which effectively acts as a copy constructor when U = T) prevent the compiler from generating the move constructor, while, on the contrary, if I user define the "real" copy constructor (by deleting it), then the move constructor is not generated implicitly (the program would not compile)? (Probably the reason is that "template version" does not respect the standard definition of copy-constructor also when T = U?).
The good thing is that that seems to apparently be what I want. In facts, I need all the copy and move constructors and all the move and copy assignment operators that the compiler would generate implicitly as if S was simply defined as template<class U> S{}; plus the template constructor for the conversions from other S<U>. By standard, can I rely on the above definition of S to have all the mentioned stuff I need? If yes, I could then avoid to "default'ing" them explicitly.
The answer is simple - There is no (!) template copy constructor. Even if the template parameter matches the parameter of a copy constructor it is no copy constructor.
See 12.8 Copying and moving class objects
A non-template constructor for class X is a copy constructor if its
first parameter is of type X&, const X&, volatile X& or const volatile
X&, and either there are no other parameters or else all other
parameters have default arguments (8.3.6). [ Example: X::X(const X&)
and X::X(X&,int=1) are copy constructors.
Similar applies to the move constructor
There is no such thing as a templated copy constructor. The regular (non-templated) copy constructor is still generated and a better match than the templated one with the signature you provided (things get more complicated with "universal" references thrown in the mix, but that is off-topic).
Copy constructors, and move constructors, are not templated. The C++ standard is specific on what constitutes a copy constructor.
From: http://en.cppreference.com/w/cpp/language/copy_constructor
A copy constructor of class T is a non-template constructor whose first parameter is T&, const T&, volatile T&, or const volatile T&, and either there are no other parameters, or the rest of the parameters all have default values.
In C++, if I define a copy constructor and operator= that take a non-const reference to the class, is the compiler supposed to still supply default versions for const reference?
struct Test {
Test(Test &rhs);
Test &operator=(Test &rhs);
private:
// Do I still need to declare these to avoid automatic definitions?
Test(const Test &rhs);
Test &operator=(const Test &rhs);
};
No, if you define a copy constructor and assignment operator, the compiler will not implicitly declare or define it's own. Note that the definition of copy-constructor allows for the argument to be taken by either const or non-const reference, so your constructor is indeed a copy-constructor. Similarly for operator=
[Omitting a big part of the details, in particular under what circumstances the implicitly declared special member functions will also be implicitly defined]
12.8 [class.copy]/2 A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).
12.8 [class.copy]/7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly.
12.8 [class.copy]/17 A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.
12.8 [class.copy]/18 If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.
No, once you declare your own copy constructor or copy assignment operator (whether or not it uses the canonical constness) the compiler won't do it for you anymore.
But doing this by non-const reference is pretty much a textbook example of violating the principle of least surprise. Everyone expects that const objects can be assigned from and that the right hand side won't be mutated. The first isn't so bad as the compiler will catch it but the second could cause a variety of hard-to-spot bugs.
If you're trying to implement move semantics and you can't use C++11, I would suggest creating a special move method and just not allowing "move" construction at all. If you can use C++11 then use the builtin rvalue references.
In this code fragment, which constructor is actually called?
Vector v = getVector();
Vector has copy constructor, default constructor and assignment operator:
class Vector {
public:
...
Vector();
Vector(const Vector& other);
Vector& operator=(const Vector& other);
};
getVector returns by value.
Vector getVector();
Code uses C++03 standard.
Code fragment looks like it is supposed to call default constructor and then assignment operator, but I suspect that this declaration is another form of using copy constructor. Which is correct?
When = appears in an initialization, it calls the copy constructor. The general form is not exactly the same as calling the copy constructor directly though. In the statement T a = expr;, what happens is that if expr is of type T, the copy constructor is called. If expr is not of type T, then first an implicit conversion is done, if possible, then the copy constructor is called with that as an argument. If an implicit conversion is not possible, then the code is ill-formed.
Depending upon how getVector() is structured, the copy may be optimized away, and the object that was created inside the function is the same physical object that gets stored in v.
Assuming that you haven't done something pathological outside of the code you are showing, your declaration is a copy-initialization, and the second part of this rule applies:
13.3.1.3 Initialization by constructor [over.match.ctor]
1 When objects of class type are direct-initialized (8.5), or copy-initialized from an
expression of the same or a derived class type (8.5), overload resolution selects the
constructor. For direct-initialization, the candidate functions are all the constructors
of the class of the object being initialized. For copy-initialization, the candidate
functions are all the converting constructors (12.3.1) of that class. The argument
list is the expression-list within the parentheses of the initializer.
For a simple test case, see Eli Bendersky's post, here: http://eli.thegreenplace.net/2003/07/23/variable-initialization-in-c/
Always remember the rule:
Whenever, an object is being created and given some value in the same single statement then it is never an assignment.
To add Further,
Case 1:
Vector v1;
Vector v(v1);
Case 2:
Vector v = getVector();
In the above two formats Case 1 is Direct Initialization while Case 2 is known as Copy Initialization.
How does Copy Initialization work?
Copy initialization constructs an implicit conversion sequence: It tries to convert return value of getVector() to an object of type Vector. It can then copy the created object into the object being initialized, So it needs a accessible copy constructor.
The copy constructor actually gets elided in this case (check this) and just the default constructor ends up getting called
EDIT:
The constructor is only sometimes elided, as per Benjamin's answer. For some reason I read that as you calling the constructor directly.
The C++ Standard Library by Nicolai M. Josuttis states:
There is a minor difference between
X x;
Y y(x) //explicit conversion
and
X x;
Y y = x; //implicit conversion
Following to say: "The former creates a new object of type Y by using an explicit conversion from type X, whereas the latter creates a new object of type Y by using an implicit conversion."
I'm a little confused about the concepts of explicit vs implicit conversion I guess. In both cases you're taking an X and pushing it into a Y per se - one uses a Y's constructor and one uses the assignment operator though.
What's the difference in how the conversion is treated in these two cases, what makes it explicit/implicit, and how does this tie into making a class constructor defined with the "explicit" key word, if at all?
one uses a Y's constructor and one uses the assignment operator though.
Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=) is never called; instead, a non-explicit one-parameter constructor (that accepts the type X as a parameter) is called.
The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.
Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.
In this case, only one-parameter constructors not marked with explicit are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.
As specified in this other answer, any constructor not marked as explicit can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y with x, but x first has to be converted to type Y, which is done with the implicit constructor.
This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit) constructor from a const char *: any function that receives a string parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string object.
Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.
You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.
More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.
one uses the assignment operator though
No, it does not. It calls the constructor directly.
The reason why one is explicit and one is implicit is because implicit conversions can happen when you don't want them to. Explicit ones cannot. The easiest example of this is bool.
Let's say that you invent some type which can be either true or false- like a pointer. Then let's further say that you decide that in order to make life easier for your users, you let it convert to bool implicitly. This is great- right up until the point where one of your users does something dumb.
int i = 0;
i = i >> MyUDT();
Oh wait- why does that even compile? You can't shift a MyUDT at all! It compiles because bool is an integral type. The compiler implicitly converted it to a bool, and then to something that can be shifted. The above code is blatantly dumb- we only want people to be able to convert to a bool, not a bool and anything else that a bool might want to do.
This is why explicit conversion operators were added to C++0x.
The first form is direct initialization. The second is copy initialization.
Copy initialization implicitly calls a converting constructor or conversion operator and then explicitly calls a copy constructor (the copy constructor call may be elided, but an accessibility check must still be performed).
Consider a third possibility, which is copy-initialization, but the conversion is explicit:
Y y = Y(x);
or
Y y = (Y)x;
The Implicit casting doesn't require any casting operator. This casting is normally used when converting data from smaller integral types to larger or derived types to the base type.
int iVal = 100;
double dVal = iVal;
The explicit converting constructor is preferred to the implicit conversion operator because in the latter case there is an additional call to the copy constructor.Implicit and Explicit converstions