class A {
public:
A() {}
A(const A& a) { cout << "A::A(A&)" << endl; }
};
class B {
public:
explicit B(A aa) {}
};
int main() {
A a;
B b(a);
return 0;
}
Why does it print "A::A(A&)"?
When was the copy constructor for "A" called? And if the code calls the copy constructor, why can I remove the copy constructor without creating a compilation error?
B(A aa) takes an A by value, so when you execute B b(a) the compiler calls the copy constructor A(const A& a) to generate the instance of A named aa in the explicit constructor for B.
The reason you can remove the copy constructor and have this still work is that the compiler will generate a copy constructor for you in cases where you have not also declared a move constructor.
Note: The compiler generated copy constructor is often not sufficient for complex classes, it performs a simple member wise copy, so for complex elements or dynamically allocated memory you should declare your own.
ยง 15.8.1
If the class definition does not explicitly declare a copy constructor, a non-explicit 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 (11.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a user-declared destructor or assignment operator.
Why the copy happens
Look at your class B c'tor:
class B {
public:
explicit B(A aa) {}
};
You receive A by value, triggering a copy during the call.
If you would have change it to (notice A & aa):
class B {
public:
explicit B(A & aa) {}
};
There wouldn't be any copy...
Default copy constructor
When you remove the c'tor, the compiler generates one for you when it can trivially do so:
First, you should understand that if you do not declare a copy
constructor, the compiler gives you one implicitly. The implicit
copy constructor does a member-wise copy of the source object.
The default c'tor is equivalent to:
MyClass::MyClass( const MyClass& other ) :
x( other.x ), c( other.c ), s( other.s ) {}
Related
Given base class A and derived class B, A has deleted move constructor:
class A {
public:
A() {}
A(const A&) = default;
A(A&&) = delete;
};
class B : public A
{
};
In such case, the following function does not compile because of deleted move constructor:
A f() {
A a;
return a;
}
but the similar function for B does not report any error:
B g() {
B b;
return b;
}
Does it mean that move constructor in B is not deleted? I want to know what is the rule in the standard.
The move constructor in B is deleted, but does not participate in overload resolution. According to cppreference:
The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following is true:
T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors);
T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors);
T has direct or virtual base class or a non-static data member with a deleted or inaccessible destructor;
T is a union-like class and has a variant member with non-trivial move constructor.
A defaulted move constructor that is deleted is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).
The second bullet point applies: B has a direct base class, A, with a deleted move constructor. So B's implicitly-declared move constructor is defined as deleted.
However, when the return statement is evaluating which constructor of B to use, the deleted move constructor is not considered but the valid copy constructor is.
The move constructor of B is deleted, as already answered by #Nathan Pierson.
The reason that you can return the local b from g is, as explained there, that the implicitly deleted move constructor of B is not participating in the overload resolution, thus the compiler selects the default copy constructor of B.
To prove the above take a look at the following code, adding a moveable only member into B:
class B : public A {
std::unique_ptr<int> ptr;
public:
B() {}
// needs this to compile:
// B(B&& b): A(b), ptr(std::move(b.ptr)) {}
};
B g() {
B b;
// now this would fail
// B doesn't have a default move ctor
// (it is implicitly deleted because of A)
// and the default copy ctor is not valid
return b;
}
Hisenter link description here
enter link description here
This question already has answers here:
Why does the implicit copy constructor calls the base class copy constructor and the defined copy constructor doesn't?
(3 answers)
Closed 11 months ago.
Consider the following example:
class A
{
public:
A()
{
cout<<"constructor A called: "<<this<<endl;
};
A(A const& other) = default;
};
class B : public A
{
public:
B()
{
cout<<"constructor B called: "<<this<<endl;
};
//This calls A's constructor
B(B const& other)
{
cout<<"B copy constructor called: "<<this<<endl;
};
//While this doesn't call A's constructor
//B(B const& other) = default;
};
int main()
{
B b;
B b2(b);
cout<<"b: "<<&b<<endl;
cout<<"b2: "<<&b2<<endl;
return 0;
}
Output:
constructor A called: 0x7fffc2fddda8
constructor B called: 0x7fffc2fddda8
constructor A called: 0x7fffc2fdddb0
B copy constructor called: 0x7fffc2fdddb0
b: 0x7fffc2fddda8
b2: 0x7fffc2fdddb0
Why is the constructor of A is called when copying B?
Shouldn't the copy constructor of A be called instead?
However, if you change class B's copy constructor to be default, the constructor of A is not called when copying which makes sense.
It will be nice if someone can give a reasonable explanation as to why.
Why is the constructor of A is called when copying B? Shouldn't the copy constructor of A be called instead?
No, it shouldn't.
A derived class must always initialize a base class. If the derived class has a constructor that is implemented explicitly by the user, but it does not explicitly call a base class constructor in its member initialization list, the compiler will make an implicit call to the base class's default constructor, regardless of the type of the derived constructor. The compiler does not make any assumption about the user's intent in implementing the derived constructor. If the user wants a specific base class constructor to be called, they need to make that call themselves.
Since B has an explicitly implemented copy constructor that lacks a member initialization list, the compiler initializes A by calling its default constructor, not its copy constructor.
IOW, this:
B(B const& other)
{
...
}
Is equivalent to this:
B(B const& other) : A()
{
...
}
NOT to this, as you are thinking:
B(B const& other) : A(other)
{
...
}
However, if you change class B's copy constructor to be default, the constructor of A is not called when copying which makes sense.
Correct, a default'ed copy constructor will call the base class's copy constructor, not its default constructor. The compiler is implicitly implementing the entire derived constructor, and so it will choose the appropriate base class constructor to call.
Below is class A which is full of different type of constructor.
If i comment the move constructor, then the copy constructor is called twice : once for passing an object to function fun by value and other by returning from the same function.
Code Snippet
class A {
int x;
public :
A() {
cout<<"Default Constructor\n";
}
A(A&& a) : x(a.x){
cout<<"Move Constructor\n";
a.x=0;
}
A(const A& a){
x=a.x;
cout<<"Copy Constructor\n";
}
A fun(A a){
return a;
}
};
int main() {
A a;
A b;
A c;
c=a.fun(b);
}
OUTPUT :
Default Constructor
Default Constructor
Default Constructor
Copy Constructor
Move Constructor
However, if the move constructor is present, it is called rather than copy constructor. Can anyone eloborate this with a good example, so that i will be clear on this concept.
I would appreciate your help.Thanks.
The standard allows a special case for the case where the expression in the return statement is an automatic duration variable. In this case, the constructor overloads are picked as if the expression in the return was an rvalue.
To be more precise, if the expression in the return statement was an automatic duration variable which was eligible for copy elision, or would be if you ignored the fact that it was a function argument, then, the compiler is required to treat it as an rvalue for the purpose of overload resolution. Note that in C++11, the return statement's expression needs to have the cv-unqualified type as the functions return type. This has been relaxed somewhat in C++14.
For example, in C++11, the following code calls the copy constructor of A, instead of the move constructor:
class A
{
};
class B
{
public:
B(A a) : a(std::move(a)){}
A a;
};
B f(A a)
{
return a;///When this is implicitly converted to `B` by calling the constructor `B(a)`, the copy constructor will be invoked in C++11. This behaviour has been fixed in C++14.
}
in the function A fun(A a) the passed in "copy" of A is basically a temporary variable. If there is no move constructor then the return value is a copy (i.e. copy constructor).
If there is a move constructor then the compiler can perform the more efficient "move" systematics on the temp variable "A a" instead.
I have class B derived from class A. I call copy constructor that I implemented myself for an object of class B. I also implemented myself a constructor for class A.
Is this copy constructor automatically called when I call copy constructor for class B ? Or how to do this ? Is this the good way:
A::A(A* a)
{
B(a);
// copy stuff
}
thanks!
You can do this with a constructor initialization list, which would look like this:
B::B(const B& b) : A(b)
{
// copy stuff
}
I modified the syntax quite a bit because your code was not showing a copy constructor and it did not agree with your description.
Do not forget that if you implement the copy constructor yourself you should follow the rule of three.
A copy constructor has the signature:
A(const A& other) //preferred
or
A(A& other)
Yours is a conversion constructor. That aside, you need to explicitly call the copy constructor of a base class, otherwise the default one will be called:
B(const B& other) { }
is equivalent to
B(const B& other) : A() { }
i.e. your copy constructor from class A won't be automatically called. You need:
B(const B& other) : A(other) { }
class A {};
class B { public: B (A a) {} };
A a;
B b=a;
I read this from http://www.cplusplus.com/doc/tutorial/typecasting/ . It says this is a implicit type conversion. From class A to class B.
I want to ask, is this also an example of copy constructor?
Thanks.
No, it's not a copy constructor. A copy constructor copies one object of one type into another of the same type:
B::B(const B& b)
{
// ...
}
As a side note, if you need a copy constructor then you also need a destructor and an assignment operator, and probably a swap function.
What B::B(A) is is a conversion function. It's a constructor that allows you to convert an object of type A into an object of type B.
void f(const B& obj);
void g()
{
A obja;
B objb = obja;
f(obja);
}
No, A copy constructor has the form
class A
{
public:
A(const A& in) {...}
}
No, a copy constructor is called when you create a new variable from an object. What you have there is two objects of different types.
The line B b = a; implies that a copy constructor is used, as if you had typed B b = B(a); or B b((B(a)));. That is, the compiler will check whether B has an accessible (public) copy constructor - whether user-defined or the default one provided by the compiler. It doesn't mean, though, that the copy constructor has to be actually called, because the language allows compilers to optimize away redundant calls to constructors.
By adding a user-defined copy constructor to B and making it inaccessible, the same code should produce a compiler error:
class A {};
class B {
public:
B (A ) {}
private:
B (const B&) {} // <- this is the copy constructor
};
A a;
B b=a;
For example, Comeau says:
"ComeauTest.c", line 10: error: "B::B(const B &)" (declared at line 6), required
for copy that was eliminated, is inaccessible
B b=a;
^