I have the following code:
#include <iostream>
#include <utility>
class A {
public:
A() { }
A(const A&, int i) { std::cout << "A copy" << std::endl; }
A(A&&, int i) { std::cout << "A move" << std::endl; }
A(const A&) = delete;
A(A&&) = delete;
};
class B : public A {
public:
B(int i) { std::cout << "B construct" << std::endl; }
B(const A& a) : A(a, 1) { std::cout << "B copy" << std::endl; }
B(A&& a) : A(std::move(a), 1) { std::cout << "B move" << std::endl; }
};
B make_b() {
return B(1);
}
int main() {
B b = make_b();
}
The compiler error reports the error that B cannot be copy-constructed (for return from make_b), because it has no copy-constructor, because A's copy-constructor is deleted.
Does B(const A&) not qualify as copy-constructor, and what is the rule that applies here?
Does the copy and move constructor always have to take one argument of the same type (and not a superclass)?
Can it have additional parameters with default values?
Can it be templated so that it can resolve to a valid copy constructor?
To allow implicit copy and move construction, is it necessary to explicitly add copy and move-constructors B(const B&) and B(B&&)?
Does B(const A&) not qualify as copy-constructor, and what is the rule that applies here?
No. A copy constructor creates another object of the same type. A is not the same type as B. If you try to construct an object of a derived class from an object of its base class, how are you supposed to initialize the derived class' members? The source object you are copying from doesn't have those members to copy!
Furthermore, B already has a copy constructor, implicitly declared by the compiler, but because the implicit definition would be ill-formed (because the base class A is not copyable) it is deleted by the compiler, so you cannot use it.
Does the copy and move constructor always have to take one argument of the same type (and not a superclass)?
Not necessarily one argument, B(const B&, int = 0) is a copy constructor, because it can be called to create a copy of a B. But B(const A&) is not a copy constructor.
Can it have additional parameters with default values?
Yes.
To allow implicit copy and move construction, is it necessary to explicitly add copy and move-constructors B(const B&) and B(B&&)?
Yes, you need to define them explicitly, because the implicit definitions the compiler would use won't work.
Since your derived type doesn't have any members, and you already have constructors that take an A, you could define them like so:
B(const B& b) : B(static_cast<const A&>(b) { }
B(B&& b) : B(static_cast<A&&>(b) { }
This creates delegating constructors which simply forward the argument to your existing constructors (using suitable casts to the base type).
About 1 :
when constructing , the compiler calls all the base classes one by one from the highest until the currently-constructed-class.
if C inherits from B inherits from A
the compiler calls A() then B() than C() ctros in order to build C object.
the same goes for copy constructors:
in your example , you called for A() copy constructor to build the "A" part of the object , but you deleted it .
the problem here is returing B by value, which calls first move ctor if exits , and move ctor if not. you deleted both
Related
I'm experiencing behavior which I don't understand in a copy constructor of derived class.
class A {
A(const A&);
public:
A() = default;
};
class B : public A {
friend class Factory;
B(const int v) : A(), m_test_val(v) {}
public:
int m_test_val;
B(const B&); // no implementation, just declaration
};
class Factory {
public:
static B create(const int v) {
return B(v);
}
};
int main() {
B b = Factory::create(2);
std::cout << b.m_test_val << '\n';
return 0;
}
The behavior I don't understand is a matter of a working copy constructor B::B(const B&); which, however, does not have any implementation.
When I use B::B(const B&) = default; instead, I get an error saying I'm using deleted function (implicitly deleted because of ill-formation) in the return statement of the Factory::create() function (The A::A(const A&) is private and without implementation on purpose).
And of course, when I use B::B(const B&) = delete;, compiler tells me I use a deleted function.
How is it possible that the copy constructor works with no implementation just with declaration?
Note: The example code is based on a much larger code that behaves the same way, hopefully I didn't leave something out.
The actual copy is elided by the compiler, which is allowed since the copy constructor is accessible. The compiler is of course under no obligation to elide this copy and if it didn't I would expect a linker error not finding the implementation of the copy constructor.
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.
Consider the code below running C++11. If I understand move semantics correctly, the copy constructor should not be called. But it is. Can someone explain why?
template<class D>
struct traced
{
public:
traced() = default;
traced(traced const&) { std::cout << typeid(D).name() << " copy ctor\n"; }
protected:
~traced() = default;
};
class A : public traced<A>{
public:
A(int x) : x_(x) {}
private:
int x_;
};
int main() {
// I thought the following two are equivalent. Apparently not.
aList.push_back(A(6)); // Prints out ".. copy ctor" ..
aList.emplace_back(6); // Does not print out " ... copy ctor"
}
aList.push_back(A(6));
This constructs a temporary A and moves it into the container. The implicitly generated move constructor of A is called, which needs to construct the base traced<A> from the base subobject of the temporary. However, trace explicitly declares a copy constructor, so it doesn't have move constructor by default, and A's move constructor nonetheless needs to perform a copy for its base class subobject.
aList.emplace_back(6);
This constructs an A directly into the container. No copy or move of any sort is involved.
struct A{
virtual void what() { cout << "Base" << endl; };
};
struct B : A {
virtual void what() { cout << "Sub" << endl; };
int m;
B() : m(10) {};
B(const A & x) : m(50) {};
};
void main() {
B b1;
B b2 = b1;
cout << "Number: "
<< b2.m << endl;
};
Why isn't b2.m = 50? I'm trying to copy a b-object and i have the copy constructor B(const A & x) : m(50). Do i need need to make a copy c'tor for the derived class ass well ? Like B(const B&x) ?? I thought since a b-object has an a part, we could use B(const A & x) : m(50) instead of the default constructor: :S
In the case where you have a function with the parameter of an A object, you can send in a B object. How come it differs with the copy constructor?
The reason is that B(const A& x) is not a copy-ctor — copy constructor for type T must always take an lvalue reference to T as the first (and have no other non-default arguments) argument. Your class has no defined copy-ctor, so the compiler generates the default one, which does a member-wise copy, hence why b2.m is the same as b1.m.
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).
Copy constructors need to be of the same type.
You haven't actually made a copy constructor. B(const A & x) is just a constructor that takes a const A by reference.
So, you don't need to make one for the derived class "as well", but "at all". As you stated, the type of this will be B(const B &x).
The default copy-ctor for classes of type B would be B(const B&). Since you haven't specified this one, the compiler kindly generates it for you.
Its different with user defined methods as those cannot be compiler generated.
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;
^