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.
Related
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)
Here is the Answer.
A()
B(int)
C(int)
~C()
~B()
~A()
But I don`t know why I get this output.
class A {
public:
A() { cout << "A()\n"; }
~A() { cout << "~A()\n"; }
};
class B : public A {
public:
B() { cout << "B()\n"; }
B(int i) { cout << "B(int)\n"; }
~B() { cout << "~B()\n"; }
};
class C : public B {
public:
C() { cout << "C()\n"; }
C(int i) : B(i) { cout << "C(int)\n"; }
~C() { cout << "~C()\n"; }
};
void main() {
C *b = new C(3);
delete b;
}
C(int) explicitly calls B(int) in its member initialization list before then logging itself in its body.
B(int) implicitly calls A() before then logging itself in its body.
Base classes are constructed before derived classes. This is why you see the constructors logged as A(), then B(int), then C(int).
~C() implicitly calls ~B() at the end after logging itself.
~B() implicitly calls ~A() at the end after logging itself.
Base classes are destructed after derived classes. This is why you see the destructors logged as ~C(), then ~B(), then ~A().
Any decent C++ book or tutorial should cover how constructors and destructors are called in relation to each other in a parent/child hierarchy.
This question already has answers here:
Calling virtual method from destructor - workaround?
(4 answers)
Closed 5 years ago.
I want to destruct an object of class B.
class A {
public:
A() {
std::cout << "construct A" << av::endl;
a = new int;
}
virtual ~A() {
std::cout << "destruct A" << av::endl;
this->clear();
}
virtual void clear() {
std::cout << "clear A" << av::endl;
delete a;
}
protected:
int *a;
};
class B : public A {
public:
B() {
std::cout << "construct B" << av::endl;
b = new int;
}
~B() {
std::cout << "destruct B" << av::endl;
}
void clear() override {
std::cout << "clear B" << av::endl;
delete b;
delete this->a;
}
private:
int *b;
};
And I want it to be done with clear() method. But when I execute following code:
A *a = new B();
delete a;
I get:
construct A construct B destruct B destruct A clear A
And clear B is never printed.
What am I doing wrong?
Informally, In ~A(); the B part is already destroyed, calling any function of B doesn't make any sense.
Effective C++ Item 9: Never call virtual functions during construction or destruction.
Once a derived class destructor has run, the object’s derived class
data members assume undefined values, so C++ treats them as if they no
longer exist. Upon entry to the base class destructor, the object
becomes a base class object, and all parts of C++ — virtual functions,
dynamic_cast s, etc., —treat it that way.
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) { // ...
I get the error: No appropriate default constructor for B. However, I don't understand why the compiler wants to call a default constructor, when I give the arguments ii and DONT want to call the default.
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int ii) { i = ii; cout << "Constructor for A\n"; }
~A() { cout << "Destructor for A\n"; }
void f() const{}
};
class B {
int i;
public:
B(int ii) { i = ii; cout << "Constructor for B\n"; }
~B() { cout << "Destructor for B\n"; }
void f() const{}
};
class C:public B {
A a;
public:
C() { cout << "Constructor for C\n"; }
~C() { cout << "Destructor for C\n"; }
void f() const {
a.f();
B::f();
}
};
class D:public B {
C c;
public:
D(int ii) { B(ii); cout << "Constructor for D\n"; }
~D() { cout << "Destructor for D\n"; }
};
int main() {
D d(47);
}
Your parent constructor should be called in the initializer list:
class D:public B {
C c;
public:
D(int ii) : B(ii)/* <- */ { cout << "Constructor for D\n"; }
~D() { cout << "Destructor for D\n"; }
};
Note the /* <- */ comment. That needs to be changed.
What you are doing right now is to create an instance of B() in you class D constructor, which is not being used:
D(int ii) { B(ii); /* <- useless*/ }
D(int ii) { B(ii); cout << "Constructor for D\n"; }
Calls the default constructor of B. The B(ii) creates an temporary object of B which gets destructed as soon as constructor of D returns, In short it does not call the constructor for Base class of object which is being constructed.
Solution:
To be able to call a particular constructor of your Base class you should use Member Initializer list.
D(int ii) : B(ii)
{
}
This code:
class C:public B
{
C() { cout << "Constructor for C\n"; }
};
attempts to call B's default constructor.
You might want:
class C:public B
{
C() : B(0) { cout << "Constructor for C\n"; }
};
but that depends on your logic.
The following is also wrong:
D(int ii) { B(ii); cout << "Constructor for D\n"; }
it should be
D(int ii) : B(ii) { cout << "Constructor for D\n"; }
Calling the base class constructor in the body of the child class constructor merely creates a temporary object which doesn't do anything. To get the behavior you expect, you must call the constructor in the initializer list.
You're creating a D, which is derived from B -- but D's ctor doesn't pass a parameter to B's constructor, which would require that B have a default ctor.
To fix this, you typically need to write D to provide a parameter to B's ctor:
class D : public B {
C C;
public:
D(int ii) : B(ii) { cout << "ctor for D\n"; }
};
You need to realize that base and member subobjects are constructed by the time you enter the body of your constructor! That is, if you have a base or a member which doesn't have a default you need to pass its argument in the member initializer list:
D(int ii): B(ii) { std::cout << "constructor for D\n"; }
The object you constructed in your body of the D constructor is just a temporary object which doesn't really serve any purpose in your case (temporary object may be useful in some cases, though).