I don't understand the output of this program :
class A {
public :
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
};
A f (A & a) {
return a;
}
int main() {
A a ;
a = f(a);
return 0;
}
I expected
A()
~A()
because I only created one A object : a. However, the output is
A()
~A()
~A()
Do you know why that is ?
FOLLOWUP QUESTION
Okay, so whenever calling f, I construct a copy of an A, so I have 1 call to the copy constructor and one call to the destructor...
Say now my main function is :
int main() {
A a ;
A b = f(a);
cout << "returning 0" << endl;
return 0;
}
I would expect the output to be
A(),
A(const A &) (for using f(a))
~A() (for deleting temporary f(a))
returning 0
~A() (destroying B)
~A() (destroying A)
But the output is
A()
A(const& A)
returning 0
~A()
~A()
Why is that ?
You only created one object explicitly, but you are creating one object here:
A f (A & a) { return a ;} //when returning A
as you are copying the object to pass it back from f, that copy is being constructed by the default copy constructor as you didn't provide one.
If you change your class to this:
class A {
public :
A () { cout << "A() " << endl;}
A (const A &) { cout << "A(const &) " << endl;}
~A () { cout << "~A ()" << endl; }
};
you will see the copy constructor being called (as you are providing one).
An answer to the follow-up question.
Destructors pair with constructors. Why do you expect two constructions and three destructions? That's not possible in a correct program.
A b = f(a);
is not an assignment (in contrast to a = f(a)), but a construction (copy initialization). You don't see a construction and destruction of a temporary object here thanks to the return value optimization (RVO): a compiler is allowed to elide an unnecessary copy and construct b as if by A b(a);.
Before C++17 this mechanism is optional. You can compile this code with GCC with -std=c++11 -fno-elide-constructors options to spot a temporary:
A() construct (a)
A(const A&) construct a temporary copy of (a)
A(const A&) construct (b) from that temporary
~A() destruct that temporary
returning 0
~A() destruct (b)
~A() destruct (a)
Since C++17 this type of copy elision is mandatory, so you'll always see only two constructions and destructions:
A() construct (a)
A(const A&) construct (b) from (a)
returning 0
~A() destruct (b)
~A() destruct (a)
Related
Output:
when B c = a why the output isnt :
cosntructor A
constructor B
copy constructor B
instead of
cosntructor A
copy constructor B
?
========================================================================================
CODE
class A {
public:
A(const A&);
A();
~A();
};
class B : public A {
public:
B(string, int, float, int);
B(const B&);
B();
~B();
};
A::A() { cout << "constructor A\n"; }
A::A(const A& old_str) { cout << "copy constructor A\n"; }
A::~A() { cout << "destructor A\n"; }
B::B() { cout << "constructor B\n"; }
B::B(const B& old_str) { cout << "copy constructor B\n"; }
B::~B() { cout << "destructor B\n"; }
int main()
{
B a;
cout << "\n\n\n";
B c = a;
cout << "\n\n\n";
}
I don t understand when "B c = a" for c aren t called both constructors, of A and B. For B c the output is constructor A constructor B which is fine, why isn t the same happening for "B c = a"
You don't see "copy constructor A" printed because you don't copy construct the A base in the B copy constructor. You can do that in the member-initialiser-list.
B::B(const B& other) : A(other) { cout << "copy constructor B\n"; }
See it live
In this declaration
B c = a;
there is used the defined by the user the copy constructor of the class B.
B::B(const B& old_str) { cout << "copy constructor B\n"; }
The copy constructor implicitly invokes the default constructor of the base class A to create its base class sub-object. As a result you have
cosntructor A
copy constructor B
In fact the copy constructor of the class B
B::B(const B& old_str) { cout << "copy constructor B\n"; }
is equivalent to
B::B(const B& old_str) : A() { cout << "copy constructor B\n"; }
The reason of your confusing is that it seems you think that in this declaration
B c = a;
at first there is created the object c using the default constructor of the class B and then the object a is assigned to the created object c using one more constructor: the copy constructor.
However only one constructor can be used to crate an object and in this case there is used the copy constructor of the class B.
In this declaration
B c = a;
there is neither assignment. a is an initializer that initializers the created object c. You could rewrite this declaration also the following way making it more clear
B c( a );
when B c = a why the output isnt :
Because B c = a; is copy-initialization. Meaning c is created as a copy of object a, using the copy constructor B::B(const B&). So the copy constructor B::B(const B&) is implicitly called by the compiler due to the statement B c = a;. Now, before entering the body of this copy constructor of B, the default constructor A::A() is also implicitly called. Hence you get the output:
constructor A
copy constructor B.
On the other hand, B a; is default initialization which uses the default constructor B::B(). So the default constructor B::B() is implicitly called due to the statement B a;. But before entering the body of this default constructor of B, the default constructor A::A() is also implicitly called. Hence you get the output:
constructor A
constructor B
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:
Default constructor with empty brackets
(9 answers)
When to use virtual destructors?
(20 answers)
Closed 3 years ago.
In the following code, I traced by using debugger I fail to understand
1. why B b2() is never called but skipped.
2. Why auto_ptr calls base (A) destructor only when object created is derived (B)?
class A {
public:
A(int x_) : _x(x_) {cout << "A::A( " << _x << ")" << std::endl; }
A(const A& src) : _x(src._x) {cout << "A::A(copy " << _x << ")";}
~A() { std::cout << "A::~A " << std::endl; }
int x() const { return _x; };
protected:
int _x;
};
class B : public A {
public:
B():A(0) {cout << "B::B( " << _x << ")";}
B(A a):A(a.x()) {cout << "B::B(A) ";}
~B() { std::cout << "B::~B "; }
};
int main() {
B b1(11); //which calls A(int) -> B(A a) -> {A::x() -> A(int)} -> ~A()}
B b2(); //It's never called, why?
std::auto_ptr<A> aptr(new B); //Calls A(0)->B()-> ~A() ==> why ~A() only but not ~B() ?
}
/*Actual Result:
B b1(11) => It prints following
A::A(11)
A::A(11)
B::B(A)
A::~A
/// Why B b2() is not called???
auto_ptr<A> aptr(new B) => It prints following. Why ~B() is not called?
A::A(0)
B::B(0)
A::~A
B b1(11) destructors => It prints following
B::~B
A::~A */
why B b2() is never called but skipped.
B b2(); declares a function, not a variable. It's called Most vexing parse.
This is how you declare a variable with default constructor:
B b2;
Why auto_ptr calls base (A) destructor only when object created is derived (B)?
Because your base class's destructor is not virtual. Classes intended to be used as a base almost always should have a virtual destructor.
Why ~B() is not called? Only A::A(0)
In C++ the destructors have to be declared as virtual or don't allow class extension.
Here is some basic C++ outline of code:
#include <cstdlib>
#include <iostream>
#include <thread>
using namespace std;
class M {
public:
M() = default;
~M() {
cout << "Called ~M" << endl;
}
};
class A {
public:
A(int z) : _z(z) {
cout << "Called A(int z)" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A() {
cout << "Called A()" << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
A(const A& a) {
cout << "Called A(const A& a)" << endl;
_z = a._z;
}
A(const A&& a) {
cout << "Called A(const A&& a)" << endl;
_z = a._z;
}
A& operator=(const A& a) {
cout << "Called A& operator=(const A& a)" << endl;
if (&a != this) {
cout << "Executed A& operator=(const A& a)" << endl;
}
}
virtual ~A() {
cout << "Called ~A" << endl;
}
int poll() const { return _z; }
private:
M _m;
int _z = 300;
};
class B : public A {
public:
// _a(10)
B() : _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
virtual ~B() {
cout << "Called ~B" << endl;
}
private:
const A& _a;
};
int main(int argc, char** argv) {
B b;
A* aPtr = &b;
A& aRef = (*aPtr);
cout << aRef.poll() << endl;
return 0;
}
from the setup above I get the following output:
Called A()
Called A(int z)
Called ~A
Called ~M
Called B()
300
Called ~B
Called ~A
Called ~M
My issue is the first line of the output (all the others make sense given the first). I am initializing the member _a in B() : _a(std::move(A(10))), this is forced as _a is const reference member. And the CTOR with int argument gets called as well, however why is the default CTOR called on A? Why no move CTOR? Therefore the temporary object simply seems constructed and destroyed, no real move is happening (as can be seen from the 300 output later on).
Now this issue does not seem related to the move per se but to the behaviour around the const reference member. Because if I change the initialization list to: B(): _a(10) I get the same issue: somehow the default object is assigned to the const reference member and the arguments in the initialization list are ignored. So for B(): _a(10) I get:
Called A()
Called A(int z)
Called B()
300
Called ~B
Called ~A
Called ~M
Basically why is the first line a default constructor? And how do I alter the code so that the 10 from the initialization appears instead of the 300 from the default?
Each object of type B has actually two subobjects of type A. One is the base-class subobject, and the other is the _a member subobject. You call the constructor for the member, but the base-class subobject is default-initialized since you haven't explicitly called its constructor in your initialization list.
You could do it by, for example, the following:
B() : A(arguments) //<--initialize the base-class subobject
, _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
Your B both contains an instance of A and derives from A (which is probably a mistake).
You're passing 10 when you construct a temporary A object, then moving that into the member _a. You're leaving the base class subobject to be default initialized.
To fix that, you need to include the base class in the member initializer list:
B() : A(1010), _a(std::move(A(10))) {
cout << "Called B()" << endl;
}
This initializes the base class subobject of B with 1010 (to distinguish it from the member object).
If I were going to do this, I'd also initialize _a directly, so the ctor would look something like:
B() : A(1010), _a(10) { // ...
#include <iostream>
using namespace std;
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
~A()
{
cout << "Destructor called" << endl;
}
};
int main()
{
A a; //Constructor called
A b = a; //Constructor not called
return 0;
}
output:
Constructor called
Destructor called
Destructor called
Constructor is called once while the destructor is called twice
What is happning here? Is this undefined behaviour?
The second line invokes what is called a Copy Constructor. Much like lawyers, if you do not have one, one will be provided for you by the compiler.
It is a special type of converter that is invoked when you initialize a variable with another of the same type.
A b(a)
A b = a
Both of these invoke it.
A(const A& a)
{
cout << "Copy Constructor called" << endl;
//manually copy one object to another
}
Add this code to see it. Wikipedia has more info.
In the snippet
A b = a
you are not calling your constructor, but the generated copy constructor:
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
A(const A& rv)
{
cout << "Copy constructor called" << endl;
// If you are not using default copy constructor, you need
// to copy fields by yourself.
this->n = rv.n;
}
~A()
{
cout << "Destructor called" << endl;
}
};
Default Copy Constructor is used to create the second instance.
When you leave the scope the destractor for both objects is called
There are two instances of object A created. One is created by a constructor, the other by the copy constructor. Since you did not explicitly define one, the compiler did the work for you.
Once the app exits, since there are two objects, the destructor method is called twice.
A b=a => A b(a) => This calls the default copy constructor of the class.