This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
Consider following code:
class Base {
public:
int bi;
Base() : bi(100) {std::cout << "\nBase default constructor ...";}
Base(int i) : bi(i) {std::cout << "\nBase int constructor: "<< bi;}
Base(const Base& b) {std::cout << "\nBase copy constructor";}
Base(Base&& b) {std::cout << "\nBase move constructor";}
};
Base getBase() {
cout << "\nIn getBase()";
return Base();
}
int main() {
Base b2(getBase());
Base b3 = Base(2);
Base b4 = getBase();
}
In spite of rvalues being given, none of the above constructions in main are calling the move constructor. Is there a way to ensure that user defined move constructor is called?
Here is what I am getting:
In getBase()
Base default constructor ...
Base int constructor: 2
In getBase()
Base default constructor ...
Base destructor: 100
Base destructor: 2
Base destructor: 100
You can use std::move() method:
Base b4 = std::move(getBase());
This ensures that move constructor is called, but in this line it prevents copy-elision to optimalize copy constructor out of there. There is no need to call any constructor, so this is more example how to not use std::move().
Related
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.
This is my code.
When I delete line 11, the output is
A(0)
B(0)
A(1)
about the last line, "A(1) ", why the second constructor of class A is called?
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// B(const B& b) { cout << "B(1)" << endl; }
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
A(0)
B(0)
A(1)
When
B(const B& b) { cout << "B(1)" << endl; }
is commented out/deleted the compiler generates a copy constructor for you. This provided copy constructor will copy all of the members of the class so in this case it will stamp out a copy constructor that looks like
B(const B& copy) : a(copy.a) {}
This is why you see a's copy constructor called.
When you do not comment out/delete
B(const B& b) { cout << "B(1)" << endl; }
You do not copy a because you do not tell it to do so. What the compiler does instead is creates a default initialization for it by transforming the constructor to
B(const B& b) : a() { cout << "B(1)" << endl; }
so the default constructor is called instead of the copy constructor.
The compiler is generating a copy constructor for you, which copies the member a. In order to copy member a, it calls its copy constructor in turn, which prints A(1).
Because object2 is initialized with the implicit copy constructor of B. An implicit copy constructor implicitly copy all the data members of the class, hence the call of the copy constructor of A, which prints "A(1)".
The issue you've run into has to do with thinking commenting out line 11 means you've deleted that constructor.
In C++, there are a couple of constructors that are automatically generated if you ended up using them, even if you didn't declare them yourself. The copy-constuctor, which has the same signature as the commented-out constructor in B, is one of them.
In your case, you end up first calling the default constructor for B, which first constructs it's member A using the default constructor as well. This should give the output you see, where the body of A's copy-constructor is reached before the body of B's because of member initialization ordering.
Then, you make a new object of type B using the assignment operator which implicitly calls the now-generated copy constructor of B. That means A's copy constructor gets called as well, which is a rule in how B's copy-constructor is auto generated. With A's copy-constuctor un-commented, it gets called with the printout.
The compiler for the class B (with the commented copy constructor) defines implicitly the default copy constructor that calls copy constructors for class members.
From the C++ 20 Standard (11.3.4.2 Copy/move constructors)
14 The implicitly-defined copy/move constructor for a non-union class
X performs a memberwise copy/move of its bases and members...
The implicitly defined default copy constructor of the class B looks like
B( const B &b ) : a( b.a )
{
}
Here is a demonstrative program
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A(0)" << endl; }
A(const A& a) { cout << "A(1)" << endl; }
};
class B {
public:
B() : a() { cout << "B(0)" << endl; }
// An analogy of the implicitly declared copy constructor
B(const B& b) : a( b.a ){}
private:
A a;
};
int main() {
B object1;
B object2 = object1;
return 0;
}
The program output will be the same as if to remove the copy constructor of class B that corresponds to the implicitly generated copy constructor by the compiler.
A(0)
B(0)
A(1)
This question already has answers here:
Assignment operator inheritance
(6 answers)
Closed 6 years ago.
Say I have this C++ code:
class Base {
public:
Base& operator=(const Base&);
};
class Derivate : public Base {
public:
};
And say I have a main where
Derivate d1;
//Something on d1
Derivate d2 = d1;
In this situation would the operator = of the base class called? I have some code that basically does such thing, but debugging with gdb I don't see any call to such operator.
Is it necessary in this case redifine the operator in the derivate class?
no in fact you are calling copy constructor because you are assigning d1 to d2 while constructing d2 thus assignment operator is not called here:
#include <iostream>
using namespace std;
class Base
{
public:
Base& operator = (const Base&);
};
Base& Base::operator = (const Base&)
{
cout << "assignment operator" << endl;
// implementation here
return *this;
}
class Derivate : public Base
{
public:
Derivate(){}
Derivate(const Derivate& rhs){cout << "copy constructor" << endl;}
};
int main()
{
Derivate d1;
//Something on d1
Derivate d2 = d1; // copy constructor not assignment operstor
//Derivate d2(d1); // is the same as above calling cpy ctor
d2 = d1; // here assignment operator is called
return 0;
}
why d2 = d1; calls the base assignment operator?
because if you don't provide a derived class assignment operator the compiler will define one for you as follows:
Derivate& operator = (const Base& rhs); // not Derivate
so this Derived one calls as you guess the base's assignment operator as long as passing a const reference instead of derived one.
assignment operator is really inherited:
make it private scoped in base class and see the result.
Im receiving error C2082: redefinition of formal parameter 'rval' in this code while trying to call base copy ctor explicitly:
#include <iostream>
using namespace std;
class Base
{
public:
Base(const Base& rhs){ cout << "base copy ctor" << endl; }
};
class Derived : public Base
{
public:
Derived(const Derived& rval) { Base(rval) ; cout << "derived copy ctor" << endl; }
// error C2082: redefinition of formal parameter 'rval'
};
int main()
{
Derived a;
Derived y = a; // invoke copy ctor
cin.ignore();
return 0;
}
However if do it like this:
Derived(const Derived& rval) { Base::Base(rval) ; cout << "derived copy ctor" << endl; }
then is OK.
Why am I asking this?
according to the answers on StackOwerflow
I do not have to use operator :: to access base copy ctor,
so why do I receive this error?
btw: I'm using visual studio 2010.
I'm having one more question:
Do I have to call base's move constructor in user defined move constructor of derived class?
To call the base constructor you need to put the call in the member initalization list
class Derived : public Base
{
public:
Derived(const Derived& rval) : Base(rval)
{
cout << "derived copy ctor" << endl;
}
};
Assuming that you mean 'move' constructor is the copy constructor - Yes. You will have to call the Base's constructor. Otherwise the definition if the base object within the derived object will not be complete. You can either call a copy constructor or a normal constructor of the base class.
Why aren't copy constructors chained (like default ctors or dtors) so that before the derived class's copy constructor is called, the base class's copy constructor is called? With default constructors and destructors, they are called in a chain from base-to-derived and derived-to-base, respectively. Why isn't this the case for copy constructors? For example, this code:
class Base {
public:
Base() : basedata(rand()) { }
Base(const Base& src) : basedata(src.basedata) {
cout << "Base::Base(const Base&)" << endl;
}
void printdata() {
cout << basedata << endl;
}
private:
int basedata;
};
class Derived : public Base {
public:
Derived() { }
Derived(const Derived& d) {
cout << "Derived::Derived(const Derived&)" << endl;
}
};
srand(time(0));
Derived d1; // basedata is initialised to rand() thanks to Base::Base()
d1.printdata(); // prints the random number
Derived d2 = d1; // basedata is initialised to rand() again from Base::Base()
// Derived::Derived(const Derived&) is called but not
// Base::Base(const Base&)
d2.printdata(); // prints a different random number
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access basedata to change it.
Is there something fundamental I'm missing about copy constructors so that my mental model is incorrect, or is there some arcane (or not arcane) reason for this design?
The copy constructor doesn't (can't) really make a copy of the object because Derived::Derived(const Derived&) can't access pdata to change it.
Sure it can:
Derived(const Derived& d)
: Base(d)
{
cout << "Derived::Derived(const B&)" << endl;
}
If you don't specify a base class constructor in the initializer list, its default constructor is called. If you want a constructor other than the default constructor to be called, you must specify which constructor (and with which arguments) you want to call.
As for why this is the case: why should a copy constructor be any different from any other constructor? As an example of a practical problem:
struct Base
{
Base() { }
Base(Base volatile&) { } // (1)
Base(Base const&) { } // (2)
};
struct Derived : Base
{
Derived(Derived&) { }
};
Which of the Base copy constructors would you expect the Derived copy constructor to call?
You can:
Derived(const Derived& d) : Base(d) {
cout << "Derived::Derived(const B&)" << endl;
}
This calls the Base copy constructor on the Base sub-object of d.
The answer for 'why' I don't know. But usually there's no answer. The committee just had to choose one option or the other. This seems more consistent with the rest of the language, where e.g. Derived(int x) won't automatically call Base(x).
That's because every constructor calls by default the default base constructor:
Derived(const Derived& d) {
cout << "Derived::Derived(const B&)" << endl;
}
will call Base().
This is defined by the standard. I for one prefer it like this rather than calling the copy constructor on the class. You can of course call it explicitly.