Consider this piece of code:
class complex{
private:
double re, im;
public:
complex(double _re, double _im):re(_re),im(_im){}
complex(complex c):re(c.re),im(c.im){}
};
I already knew that the copy constructor complex(complex c) will cause infinite recursion.
However, it should only pick const reference copy constructor complex(const complex &c) as the function for copying, since this is the default behavior if it is not explicitly specified. Every thing else is excluded, such as complex(complex c).
Why does it apply the function with pass by value here? Or both are copy constructors, except the pass by value cannot be modified and is used to pass to other functions rather than its constructor?
I think in Java, it is permitted to do like that, since it will just copy the object into the constructor.
A copy constructor must be in on of the following forms:
T(T&);
T(const T&);
That is, a constructor is a copy constructor only if it takes a single parameter of reference class type. A constructor that takes a single parameter of class type by-value is, by definition, not a copy constructor (edit) -- and in fact is illegal, as pointed out by Cat Plus Plus.
12.1 : Constructors
10/A copy constructor for a class X is a constructor with a first parameter of type X& or of type const X&
Beyond this Standardese, however, is a fundamental error in your understanding of the copy constructor. Consider the following code:
class Foo
{
public:
Foo() {}
Foo(Foo f) {/*...*/};
};
int main()
{
Foo f1;
Foo f2(f1);
}
When f2 is constructed f1 is passed by-value. In order to evaluate the parameters for the constructor call, f1 must be copied. So, you see there is a paradox here. In order to call the copy constructor, you must make a copy. In order to make a copy, you must call the copy constructor...
The above must call the constructor with an argument by-value simply because that is what the type of the parameter is: it's a Foo by-value. It it were not by-value, it would have to be either by reference, which looks like this:
Foo(Foo& rhs)
/* or like this: */ Foo(const Foo& rhs);
...or it must take it by pointer, which looks like this:
Foo(Foo* prhs)
...but, in the latter case, this is obviously not a copy constructor given the definition above.
complex(complex) is not a copy constructor. It's ill-formed, and should be rejected by compiler. There is no infinite recursion, because you simply cannot define a constructor like that.
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).
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. A member
function template is never instantiated to produce such a constructor signature.
Answer to Java question since all other possible explanations are given:
//java code
public class Bar{
private int foo;
public Bar() { } // public no-args constructor
public Bar(Bar b) { foo = b.foo; } // copy constructor
}
In Java objects are references and not value objects like they are in C++. In C++ when you copy an object you create a copy of the object's state, internal variables etc. In Java it simply copies the reference. The object's state is not copied so there is actually no need to call the copy constructor like you do it in C++.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the point in defaulting functions in C++11?
C++11 introduced defaulted methods (e.g. void myMethod() = default;).
What does it do to methods (how do methods behave after being defaulted). How do I use them properly (what are its uses)?
There are a number of class members that are considered "special member functions" by the C++ standard. These are:
The default constructor (a constructor that can be called with no parameters).
The copy constructor (a constructor that can be called with one parameter that is the object type as an lvalue reference).
The copy assignment operator (an operator= overload that can be called with one parameter that is the object type as either an lvalue reference or a value).
The move constructor (a constructor that can be called with one parameter that is the object type as an rvalue reference).
The move assignment operator (an operator= overload that can be called with one parameter that is the object type as either an rvalue reference or a value).
The destructor.
These member functions are special in that the language does special things with them on types. Another thing that makes them special is that the compiler can provide definitions for them if you do not. These are the only functions that you can use the = default; syntax on.
The issue is that the compiler will only provide a definition under certain conditions. That is, there are conditions under which a definition will not be provided.
I won't go over the entire list, but one example is what others have mentioned. If you provide a constructor for a type that is not a special constructor (ie: not one of the constructors mentioned above), a default constructor will not be automatically generated. Therefore, this type:
struct NoDefault
{
NoDefault(float f);
};
NoDefault cannot be default constructed. Therefore, it cannot be used in any context where default construction is needed. You can't do NoDefault() to create a temporary. You can't create arrays of NoDefault (since those are default constructed). You cannot create a std::vector<NoDefault> and call the sizing constructor without providing a value to copy from, or any other operation that requires that the type be DefaultConstructible.
However, you could do this:
struct UserDefault
{
UserDefault() {}
UserDefault(float f);
};
That would fix everything, right?
WRONG!
That is not the same thing as this:
struct StdDefault
{
StdDefault() = default;
StdDefault(float f);
};
Why? Because StdDefault is a trivial type. What does that mean? I won't explain the whole thing, but go here for the details. Making types trivial is often a useful feature to have, when you can do it.
One of the requirements of a trivial type is that it does not have a user-provided default constructor. UserDefault has a provided one, even though it does the exact same thing as the compiler-generated one would. Therefore, UserDefault is not trivial. StdDefault is a trivial type because = default syntax means that the compiler will generate it. So it's not user-provided.
The = default syntax tells the compiler, "generate this function anyway, even if you normally wouldn't." This is important to ensure that a class is a trivial type, since you cannot actually implement special members the way the compiler can. It allows you to force the compiler to generate the function even when it wouldn't.
This is very useful in many circumstances. For example:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
private:
std::unique_ptr<SomeType> m_ptr;
};
We must write every one of these functions to make the class copy the contents of the unique_ptr; there's no way to avoid that. But we also want this to be moveable, and the move constructor/assignment operators won't automatically be generated for us. It'd silly to re-implement them (and error-prone if we add more members), so we can use the = default syntax:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing(UniqueThing &&ptr) = default;
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
UniqueThing &operator =(UniqueThing &&ptr) = default;
private:
std::unique_ptr<SomeType> m_ptr;
};
Actually, default can only apply to special methods - i.e. constructors, destructors, assignment operator:
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
1 A function definition of the form:
attribute-specifier-seqopt decl-specifier-seqopt declarator = default ;
is called an explicitly-defaulted definition. A function that is explicitly defaulted shall
— be a special member function,
— have the same declared function type (except for possibly differing ref-qualifiers and except that in
the case of a copy constructor or copy assignment operator, the parameter type may be “reference to
non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared,
and
— not have default arguments.
They behave the same as if the compiler generated them and are useful for cases like:
class Foo{
Foo(int) {}
};
here, the default constructor doesn't exist, so Foo f; wouldn't be valid. However, you can tell the compiler that you want a default constructor without the need to implement it yourself:
class Foo{
Foo() = default;
Foo(int) {}
};
EDIT: Pointed out by #Nicol Bolas in the comments, this truly doesn't explain why you'd prefer this over Foo() {}. What I'm guessing is: if you have a class w/ implementations separated in an implementation file, your class definition (if you don't use =default) would look like:
class Foo{
Foo();
Foo(int);
};
What I'm assuming is that the =default is meant to provide an idiomatic way of telling you "we're not doing anything special in the constructor". With the above class definition, the default constructor could very well not value-initialize the class members. With the =default you have that guarantee just by looking at the header.
Using = default on a constructor or copy-constructor means that the compiler will generate that function for you during compile-time. This happens normally when you exclude the respective functions from your class/struct. And in the case where you define your own constructor, this new syntax allows you to explicitly tell the compiler to default-construct the constructor where it normally won't. Take for instance:
struct S {
};
int main() {
S s1; // 1
S s2(s1); // 2
}
The compiler will generate both a copy-constructor and a default-constructor, thus allowing us to instantiate an S object like we did (1) and copy s2 into s1 (2). But if we define our own constructor, we find that we are unable to instantiate in the same way:
struct S {
S(int);
};
int main() {
S s; // illegal
S s(5); // legal
}
This fails because S has been given a custom-defined constructor, and the compiler won't generate the default one. But if we still want the compiler to give us one, we can explicitly convey this using default:
struct S {
S(int);
S() = default;
S(const S &) = default;
};
int main() {
S s; // legal
S s(5); // legal
S s2(s); // legal
}
Note, however, that only certain functions with certain function-signatures can be overloaded. It follows that this will fail because it is neither a copy-constructor nor a default-constructor or a move or assignment operator:
struct S {
S(int) = default; // error
};
We are also able to explicitly define the assignment operator (just like the default/copy-constructor, a default one is generated for us when we do not write out our own). So take for example:
struct S {
int operator=(int) {
// do our own stuff
}
};
int main() {
S s;
s = 4;
}
This compiles, but it won't work for us in the general case where we want to assign another S object into s. This is because since we wrote our own, the compiler doesn't provide one for us. This is where default comes into play:
struct S {
int operator=(int) {
// do our own stuff
}
S & operator=(const S &) = default;
};
int main() {
S s1, s2;
s1 = s2; // legal
}
But technically it's superfluous to define the assignment operator, copy, or move constructor as default when there is no other function "overriding" it as the compiler will provide one for you in that case anyway. The only case in which it won't provide you one is where you define your own one (or variation thereof). But as a matter of preference, asking the compiler to provide a default function using the new aforementioned syntax is more explicit and easier to see and understand if intentionally left out for the compiler.
Say we have a class A that contains as a member of the same class:
Class A{
const A &a;
}
I want to create a parametized constructor that passed the value of that member, but I do not want to define the copy constructor of the class.
A(const A& memberA): a(memberA) {}
How could indicate the compiler such thing?
Thanks
A constructor that can take just a reference to the class it constructs is a copy constructor, whether you want it to be one or not. Copy constructors are defined thus:
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.
You could declare it explicit to restrict how the class can be copied (preventing A a = A() for example), but it's still a copy constructor as long as it has that signature.
You can define this constructor as explicit.
(That's a good rule for all constructors that can be called with one parameter.)
Am I doing this right? This is a highly simplified version of my code:
class Logger {
public:
Logger(std::ostream) { /*...*/}
};
class Driver {
public:
Driver() : m_logger(std::cout) {}
Driver(Logger& logger) : m_logger(logger) {}
private
Logger m_logger;
};
So my class Driver has a member of type Logger. When I call the argument-less constructor Driver(), the instance of Driver creates its own instance of Logger using std::cout.
When calling Driver(Logger) the instance shall use an already existing instance of Logger passed as a reference.
The above code compiles using g++. Although I understand what happens when calling Driver(), I don't get what happens when calling Driver(Logger). Logger has no constructor which accepts a reference on Logger as argument ("copy constructor"). So what is executed when calling Driver(Logger)?
A trivial copy constructor for Logger is synthesised for you, unless you declare one yourself.
This is much the same as how a trivial default constructor is synthesised for you (if you don't declare a default user-defined constructor).
[C++11: 12.8/7]: If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor
is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition
struct X {
X(const X&, int);
};
a copy constructor is implicitly-declared. If the user-declared constructor is later defined as
X::X(const X& x, int i =0) { /* ... */ }
then any use of X’s copy constructor is ill-formed because of the ambiguity; no diagnostic is required.
[C++11: 12.8/8]: The implicitly-declared copy constructor for a class X will have the form
X::X(const X&)
if
each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&.
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
When you construct a Driver with a Logger argument, it is taken by reference and the Logger copy constructor is invoked to initialize m_logger, so you end up with a new Logger that is a copy of the argument. The copy constructor is provided by the compiler unless you explicitly make Logger non-copyable, by declaring the copy constructor private.
Seems perfectly valid, except that you should make the logger argument a const reference; you're going to copy it, after all, not modify it.
While learning the concept of "copying members", the book gives the following statement.
In addition, a default assignment cannot be generated if a nonstatic member is a reference, a const,or a user-defined type without a copy assignment.
I do not quite understand what does this statement really want to deliver? Or which kind of scenario does this statement refer to? Thanks.
This statement has to do with the compiler automatically generating the default assignment operator function for a class you write (i.e. user-defined type). The default assignment works by copying all the members over to a new instance. This statement covers three cases where a default assignment would not be able to be generated:
1) When a member is a reference (i.e. refers to an instance of a variable, like a pointer)
class Foop {
int& reference;
};
2) When a member variable is constant
class Foople {
const int someConst;
};
3) When some other class does not have a copy-constructor and you have a member variable of that type, obviously it cannot be copied using the default method (which uses copy-constructors)
class Uncopyable {
private:
Uncopyable(Uncopyable const& other);
};
class Fleep {
Uncopyable uncopyable;
};
In these cases, you would need to write your own assignment operator (or possibly do without).
If you have a member in your class which is not static (shared between all instances of class), and is either
a reference (high level pointer)
a constant
a user-defined type with dynamic data (the same as the class we're talking about)
The default = operator and copy constructor is no longer valid and you should write manual versions of those.
class ClassA
{
int& _myReferenceMember;
const int _myConstant;
ClassB _objWhereClassBHasNoCopyConstructor;
}
Above are examples of the three cases you described. And as you quoted, you must write a custom copy constructor (if you want a copy constructor at all) in such a case, or change your member variables.
It refers to the distinction between:
class A { int a; };
and
class B { int& a; };
For class A, the compiler will generate an implicit assignment operator (=), but in the case of B, it cannot. This is because references in C++ don't have pointer semantics. i.e. you cannot change what a reference point to after it is constructed, hence, the implicit copy constructor would not be able to copy that member. The same thing goes for const members (which are explicitly marked as being immutable) and members which don't have a assignment operators (implicit or explicit).
The default assignment operator for A would essentially do this:
class A
{
A& operator=(A const& a_) { a = a_.a; }
int a;
};
class Foo
{
public:
explicit Foo() {}
explicit Foo(Foo&) {}
};
Foo d = Foo();
error: no matching function for call to 'Foo::Foo(Foo)'
I tried changing Foo(Foo&) to Foo(Foo) as the error suggests, which AFAIK is not a valid constructor, and sure enough I get:
error: invalid constructor; you probably meant ‘Foo (const Foo&)’
What gives? How do I resolve this? (This is on GCC by the way)
There are two questionable things that you have in your copy constructor.
First, you've made the copy-constructor explicit (which is a questionable thing to do), so you would (in theory) need to do:
Foo d( (Foo()) );
Second, your copy constructor takes a reference and not a const reference which means that you can't use it with a temporary Foo.
Personally, I'd just remove explicit from the copy-constructor and make it take a const reference if possible.
Note that the explicit on your default constructor has no effect.[*] explicit only has an effect on constructors that can be called with a single parameter. It prevents them being used for implicit conversions. For constructors that take only zero or only two or more parameters, it has no effect.
[Note: there can be a difference between:
Foo d;
and
Foo d = Foo();
but in this case you have a user-declared default constructor so this doesn't apply.]
Edit:
[*] I've just double checked this and 12.3.1 [class.conv.ctor] says that you can make a default constructor explicit. In this case the constructor will be used to perform default-initialization or value-initialization. To be honest, I don't understand the value of this as if you have a user-declared constructor then it's a non-POD type and even local objects of non-POD type are default-initialized if they don't have an initializer which this clause says can be done by an explicit default constructor. Perhaps someone can point out a corner case where it does make a difference but for now I don't see what effect explicit has on a default constructor.
You don't want to mark either of those constructors as explicit - the compiler needs to use both of them, particularly the copy constructor, implicitly. What are you trying to achieve by marking them explicit?
First, neither the default constructor nor the copy constructor should ever be explicit. You only need to make a constructor explicit if it takes a single argument of some other type, to prevent implicit conversion from that type. The copy constructor takes a reference to the class itself, so there is no danger of an unwanted conversion.
Second, make sure that the copy constructor takes a const reference.
Third, Foo f; is the right way to have a default-constructed object of class foo. Note that Foo f(); is wrong, because the compiler will interpret that as a declaration of function f() which returns an object of class Foo.
Fourth, if you have written your own copy constructor, then you should also write the assignment operator.
class Foo
{
Foo() {} // no need to make explicit. Nothing to convert from.
Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo
explicit Foo(int a) {} // need explicit to prevent accidental passing of an int
// to a function that takes Foo as an argument
};
Try without the explicit? I think that:
Foo foo = Foo()
creates an implicit copy, thus the explicit copy constructor doesn't get triggered.
Edit:
This is only half the answer. See Charles Bailey or UncleBens post for why const is necessary.
A copy constructor shouldn't be explicit (which makes it uncallable here and in many other perfectly reasonable contexts, such as when passing or returning by value).
Next it should take the argument by const reference, since otherwise it can't bind to temporaries.
Foo f = Foo();
^^^^^
|
--- this is a temporary that cannot be passed to a function
that accepts a non-const reference
Furthermore, there is no reason to make the default constructor explicit: this keyword only makes sense for constructors (other than the copy constructor) that can be called with exactly one argument, in which case it prevents implicit conversions of other types into Foo via that constructor. For example, if a constructor taking an int were explicit, situations like these wouldn't compile:
Foo f;
f = 1; //assuming no operator= overload for (types convertible from) int
//this implicitly performs f = Foo(1);
Foo g = 10;
void x(Foo);
x(20);
All in all:
class Foo
{
public:
Foo();
Foo(const Foo&);
//...
};
Foo x = Foo();
And furthermore, if neither of those constructors is meant to do anything, you needn't define them at all - the compiler will provide them automatically (if you define any other constructors, the default constructor will not be automatically generated, though).
Foo d = Foo();
should be
Foo d;
The first line creates a Foo instance and then copies it to d;
Your problem is in the instantiation. You don't need Foo d = Foo(); for a default constructor.
Keep your class the same, but try this for instantiation:
Foo d;
In fact, you don't even need Foo d = Foo(arguments); for constructing with parameters. That should be like this:
Foo d(arguments);
The compiler is telling you... Use this:
Foo(const Foo&) {}
You can cure the problem in either of two ways. One (already suggested by Randolpho) is to eliminate using the copy ctor. The other is to write a proper copy ctor:
Foo (Foo const &) {}
You generally want to do both.
Edit: Looking at it, my last comment is easy to mis-construe. Quite a few classes do not need a copy ctor at all, but if you do need a copy ctor, it should normally have the form above (not explicit, and taking a const reference as the parameter).
class Foo
{
public:
explicit Foo() {}
explicit Foo(const Foo&) {}
};
Foo d = Foo()