Consider this piece of code:
#include <vector>
#include <iostream>
using namespace std;
class Base
{
char _type;
public:
Base(char type):
_type(type)
{}
~Base() {
cout << "Base destructor: " << _type << endl;
}
};
class uncopyable
{
protected:
uncopyable() {}
~uncopyable() {}
private:
uncopyable( const uncopyable& );
const uncopyable& operator=( const uncopyable& );
};
class Child : public Base, private uncopyable
{
int j;
public:
Child():
Base('c')
{}
~Child() {
cout << "Child destructor" << endl;
}
};
int main()
{
vector<Base> v;
Base b('b');
Child c;
v.push_back(b);
v.push_back(c);
return 0;
}
The output on my system is:
Base destructor: b
Child destructor
Base destructor: c
Base destructor: b
Base destructor: b
Base destructor: c
My questions are:
Why is the destructor of Base (with type b) called three times instead of two (do we have more than two copies of object b)?
What happens when we copy an object of type Child, considering the copy-constructor of one of its parents is private. Is it undefined behavior?
I was expecting to get a compile-time error whenever I try to copy an object of type Child. I thought the child's default copy-constructor would try to call the private copy-constructor of the Uncopyable class and cause compilation error. Why doesn't it give compile errors?
The reason the code is designed this way is because the Child class is huge.
The desired behavior is throwing away the child data whenever a client tries to copy a Child object (calling the destructor of Child without calling the destructor of Base).
This piece of code achieves that, but I guess it results in undefined behavior and has memory leak (never calls the destructor of Child for the copied instance).
Here is what happens in your code:
int main()
{
vector<Base> v; // 1
Base b('b'); // 2
Child c; // 3
v.push_back(b); // 4
v.push_back(c); // 5
return 0;
} // 6
line 1: vector v constructed
line 2: Base b constructed (calling Base's constructor)
line 3: Child c constructed (calling Child's constructor and Base's constructor)
line 4: v is current at maximum capacity and needs to be resized.
Memory is allocated for 1 element of Base by v.
Base b copied into v[0] (calling Base's copy constructor).
line 5: v is again at maximum capacity and needs to be resized.
Memory is allocated for 2 elements of Base by v.
The old v[0] is copied into the new v[0] (calling Base's copy constructor).
The old v[0] is deleted (calling Base's destructor ("Base destructor: b")).
Child c is copied into v[1] (calling Base's copy constructor).
line 6: c, b, and v run out of scope.
Child c is deleted (calling Child's destructor ("Child destructor") then Base's destructor ("Base destructor: c").
Base b is deleted (calling Base's destructor ("Base destructor: b")).
Base v[0], v[1] are deleted (calling Base's destructor twice ("Base destructor: b", "Base destructor: c")).
There is no memory leak - for every constructor in the above sequence a corresponding destructor is called.
Additionally, you seem to be very confused about copy constructors. Child c gets passed to push_back as a Base& - which then calls Base's copy constructor as expected. Since Base's implicit copy constructor is not virtual or overriden, having Child derive from uncopyable does nothing to change this.
Note that a vector<Base> cannot ever store an object of type Child; it only knows to allocate enough memory for a Base. What occurs when assigning an instance of Child to a Base is known as slicing, which, while often unintended and misunderstood, seems like it may actually be what you want in your described scenario.
I was expecting to get a compile-time error whenever I try to copy an object of type Child.
You aren't copying a Child object. When you put Child c into a vector<Base>, only the Base gets copied. It's basically the same as executing b = c;. If you do copy/assign Child you will get an error.
Child d = c; // compile error
The default copy constructor will call the copy constructors of any base class and member objects and do a bitwise copy for primitives and pointers.
EDIT: The answer is wrong.. currently editing to a better response.
Why is the destructor of Base (with type b) called three times instead of two (do we have more than two copies of object b)?
Most likely is that the Vector is making a copy of b. Vectors do that often.
What happens when we copy an object of type Child, considering the copy-constructor of one of its parents is private. Is it undefined behavior?
No. The copy constructor of C will call the copy constructor of the base classes. So if base class copy constructors are private, it will not compile.
I need to get a compile-time error whenever I try to copy an object of type Child while, permitting copying of Base class objects. What is the best way to do that?
Declare a private copy-constructor for Child like so:
private:
Child(const Child& a) {
throw "cannot make a copy";
}
The desired behavior is throwing away the child data whenever a client tries to copy a Child object (calling the destructor of Child without calling the destructor of Base).
Not sure what you mean. The copy constructor means creating a new object. You cannot do operations on the (old) object.
Related
I came across some odd code like the following:
class B {
int* ab;
///...
~B() { /// not virtual
delete ab;
}
///...
}
class D : public B {
int* ad;
///...
~D() {
delete ab;
delete ad;
}
///...
}
But in my opinion, the destructor of the subclass will definitely call the destructor of its base class. So, I think there is no need for the subclass to deallocate resources allocated by its base class. Thus, there is no need to add delete ab in the destructor of class D. What's worse, delete one object twice is wrong.
However, this code works fine in our systmem for a very long time and passes our whole test cases. Are there any other considerations in this kind of odd implementation?
So I wander, if the destructor of subclass is called, then ,no matter what happened, the destructor of base class will be called later on.
Or, after the execution of subclass's destructor, is there any way to stop the execution of base class's destructor?
You are correct that the B class destructor will be called if the a D instance is destructed. The call to delete ab; in the D dtor is a bug.
The other thing to consider with this code, is that because B's dtor is not virtual you cannot delete an instance of D via a B pointer.
The DTOR for D is incorrect in both cases though, and should definitely be changed. If you plan on using the hierarchy of classes polymorphically then you also must change the B DTOR to be virtual.
On the last line of a destructor, I have a diagnostic type message which takes a printf-like form:
"object destroyed at %p", this
I have concerns though about how well this is defined at such a point.
Should I have such reservations? Is the behaviour well-defined?
According to the C++ Standard (12.4 Destructors)
8 After executing the body of the destructor and destroying any
automatic objects allocated within the body, a destructor for class
X calls the destructors for X’s direct non-variant non-static data
members, the destructors for X’s direct base classes and, if X is the
type of the most derived class (12.6.2), its destructor calls the
destructors for X’s virtual base classes.
So your code is well-formed. All destructors of non-static data members and base classes are called after executing the body of the destructor.
Well, the pointer itself certainly still exists (it's just an address, after all). There should be no problem to print the pointer value.
On the other hand, everything that you did in the destructor has already happened. Attributes may already have been delete'd, etc, so you have to avoid anything that accesses those.
This has perfectly well defined behaviour. Consider that the this pointer can be used implicitly or explicitly throughout the destructor, e.g. whenever you access a member variable for things like delete ptr_;. After the destructor returns, the members are destroyed in reverse order of declaration/creation then the base destructors invoked.
As you might now, you can access your class members from the destructor. This would not be working if the this pointer was invalid. So you can safely assume that the address this points to is still the same that you might have printed in the constructor.
Inside the destructor the this pointer is well defined, as are all the members and bases (that will be destroyed in construction reverse order after the destructor return). So printing the address it refers is not UB.
The only thing is that the object itself cannot be assumed anymore as "polymorphic", since the derived components had already been destroyed.
class A
{
public:
virtual void fn() { std::cout << "A::fn" << std::endl; }
virtual ~A() { fn(); } //< will call A::fn(), even if B is destroying
};
class B: public A
{
public:
virtual void fn() { std::cout << "B::fn" << std::endl; }
virtual ~B() {}
};
int main()
{
B b;
A& a = b;
a.fn(); //< will print B::fn(), being A::fn virtual and being B the runtime-type of the a's referred object
return 0; //< will print A::fn() from b's A's component destructor
}
I was under impression that it's impossible, see for example:
Calling the constructor of the base class after some other instructions in C++
But the following program runs and produces two lines of "Constructor Person":
#include <iostream>
class Person
{
public:
Person()
{
std::cout << "Constructor Person" << std::endl; }
};
class Child : public Person
{
public:
Child()
{
c = 1;
Person();
}
int c;
};
int main()
{
Child child;
return 0;
}
The first one is implicit call of the default constructor, that's clear. What about the 2nd one - does it mean that the action described in the title is legitimate? I use Visual C++ 2010.
The call inside the child class constructor is not calling the base class constructor, it is creating a temporary, unnamed and new object of type Person. It will be destroyed as the constructor exits. To clarify, your example is the same as doing this:
Child() { c = 1; Person tempPerson; }
Except in this case, the temporary object has a name.
You can see what I mean if you modify your example a little:
class Person
{
public:
Person(int id):id(id) { std::cout << "Constructor Person " << id << std::endl; }
~Person(){ std::cout << "Destroying Person " << id << std::endl; }
int id;
};
class Child : public Person
{
public:
Child():Person(1) { c = 1; Person(2); }
int c;
};
int main() {
Child child;
Person(3);
return 0;
}
This produces the output:
Constructor Person 1
Constructor Person 2
Destroying Person 2
Constructor Person 3
Destroying Person 3
Destroying Person 1
The following is an excerpt from "Accelerated C++":
"Derived objects are constructed by:
1. Allocating space for the entire object (base class members as well as derived class members);
2. Calling the base-class constructor to initialize the base-class part of the object;
3. Initializing the members of the derived class as directed by the constructor initializer;
4. Executing the body of the derived-class constructor, if any."
Summarizing the answers and comments: Calling a constructor of the base class from a subclass' constructor body is impossible in the sense that #2 above must precede #4.
But we still can create a base object in the derived constructor body thus calling a base constructor. It will be an object different from the object being constructed with the currently executed derived constructor.
You can't call it from the body of the child constructor, but you can put it into the initializer list:
public:
Child() : Person() { c = 1; }
Of course it's not helpful to call the default constructor of the parent because that will happen automatically. It's more useful if you need to pass a parameter to the constructor.
The reason you can't call the constructor from the body is because C++ guarantees the parent will be finished constructing before the child constructor starts.
The answers to this question while usually technically true and useful, don't give the big picture. And the big picture is somewhat different than it may seem :)
The base class's constructor is always invoked, otherwise in the body of the derived class's constructor you'd have a partially constructed and thus unusable object. You have the option of providing arguments to the base class constructor. This doesn't "invoke" it: it gets invoked no matter what, you can just pass some extra arguments to it:
// Correct but useless the BaseClass constructor is invoked anyway
DerivedClass::DerivedClass() : BaseClass() { ... }
// A way of giving arguments to the BaseClass constructor
DerivedClass::DerivedClass() : BaseClass(42) { ... }
The C++ syntax to explicitly invoke a constructor has a weird name and lives up to this name, because it's something that's very rarely done - usually only in library/foundation code. It's called placement new, and no, it has nothing to do with memory allocation - this is the weird syntax to invoke constructors explicitly in C++:
// This code will compile but has undefined behavior
// Do NOT do this
// This is not a valid C++ program even though the compiler accepts it!
DerivedClass::DerivedClass() { new (this) BaseClass(); /* WRONG */ }
DerivedClass::DerivedClass() { new (this) BaseClass(42); /* WRONG */ }
// The above is how constructor calls are actually written in C++.
So, in your question, this is what you meant to ask about, but didn't know :) I imagine that this weird syntax is helpful since if it were easy, then people coming from languages where such constructor calls are commonplace (e.g. Pascal/Delphi) could write lots of seemingly working code that would be totally broken in all sorts of ways. Undefined behavior is not a guarantee of a crash, that's the problem. Superficial/obvious UB often results in crashes (like null pointer access), but a whole lot of UB is a silent killer. So making it harder to write incorrect code by making some syntax obscure is a desirable trait in a language.
The "second option" in the question has nothing to do with constructor "calls". The C++ syntax of creating a default-constructed instance of a value of BaseClass object is:
// Constructs a temporary instance of the object, and promptly
// destructs it. It's useless.
BaseClass();
// Here's how the compiler can interpret the above code. You can write either
// one and it has identical effects. Notice how the scope of the value ends
// and you have no access to it.
{
BaseClass __temporary{};
}
In C++ the notion of a construction of an object instance is all-permeating: you do it all the time, since the language semantics equate the existence of an object with that object having been constructed. So you can also write:
// Constructs a temporary integer, and promptly destructs it.
int();
Objects of integer type are also constructed and destructed - but the constructor and destructor are trivial and thus there's no overhead.
Note that construction and destruction of an object this way doesn't imply any heap allocations. If the compiler decides that an instance has to be actually materialized (e.g. due to observable side effects of construction or destruction), the instance is a temporary object, just like the temporaries created during expression evaluation - a-ha, we notice that type() is an expression!
So, in your case, that Person(); statement was a no-op. In code compiled in release mode, no machine instructions are generated for it, because there's no way to observe the effects of this statement (in the case of the particular Person class), and thus if no one is there to hear the tree fall, then the tree doesn't need to exist in the first place. That's how C++ compilers optimize stuff: they do lot of work to prove (formally, in a mathematical sense) whether the effects of any piece of code may be unobservable, and if so the code is treated as dead code and removed.
Yeah, I know this is a year old but I found a way to do it. This may not be the best practice. For example, destroying the base class instance from within the derived class constructor sounds like a recipe for disaster. You could skip the destructor step, but that may lead to a memory leak if the base class constructor does any allocation.
class Derived : public Base
{
public:
Derived()
{
// By the time we arrive here, the base class is instantiated plus
// enough memory has been allocated for the additional derived class stuff.
// You can initialize derived class stuff here
this->Base::~Base(); // destroy the base class
new (this) Base(); // overwrites the base class storage with a new instance
}
};
#include<iostream>
using namespace std;
class A
{
public:
int i;
A() {cout<<"A()"<<endl;}
~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
int j;
B(): j(10)
{
this->i=20;
this->~A();
}
};
int main()
{
B abc;
cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main
Two questions:
How come A's destructor gets called like an ordinary function instead of destroying the object? (or is it some kind of rule that the base class will be destroyed only if the child class's destructor calls the base class's destructor?) I was trying out this sample code to find out how the destructor works. So if simply calling the destructor function does not destruct the object, then there is obviously some other kind of call that calls the destructor and only then the object is destructed. What's so special in that kind of call and what call is it?
Is there a way to have an initialization list for A in B's constructor? Something like this:
class B:public A
{
B(): j(10), A():i(20) {}
};
Destructor is like any other normal function which you can call (but you should never do it unless you use a placement new). When you call delete on a object two things happen: Destructor is called for cleanup and then operator delete is called to release the memory allocated for the object. Here the second step is not happening.
No, you can not call it like that. What you can do is some thing like this:
class A
{
public:
A(int n) : i(n){}
};
class B : public A
{
public:
B() : A(20), j(10){}
};
The base class's destructor should be virtual. Here, as it's created on the stack, it's not problem, but anyway..
No, but you can call the class A() constructor in the initialize list of B's constructor, like this:
B(): A( .. ), ...
A* a = new B();
//..
delete a;
will not call B's destructor unless class A destructor is virtual. That's why STL containers should not be derived - theirs destructors are not virtual.
#Nav: no, your understanding of "destroyed" is just wrong. When an object's destructor is called, the object is destroyed. You seem to believe that the memory it resided in evaporates entirely, but that never happens. The object no longer exists, but some garbage data is typically left over by the object, and if you're willing to break the rules of C++ and invoke undefined behavior, then you can read those leftover bytes, and they'll look like the object, and because there are no runtime checks on whether you're accessing a valid object, you can often treat them as an object. Which you do.
It's illegal, it's undefined behavior, but in practice it often works.
Once again, a destructor does not physically vaporize the memory. Your RAM still has the same capacity after a destructor has executed. Conceptually, the object no longer exists once the destructor has run. But the data it contained is still there in memory.
For point:
This is an undefined behaviour but only ~A() is called though an instance of class B because ~A() is not declared virtual. See more on Wikipedia.
No. For derived classes, first call your parent class, then assign parameters.
For point 1) on Wikipedia:
having no virtual destructor, while
deleting an instance of class B will
correctly call destructors for both B
and A if the object is deleted as an
instance of B, an instance of B
deleted via a pointer to its base
class A will produce undefined
behaviour.
Example (for point 2):
B(): A(), j(10) {}
or
B(): A() {j = 10;}
1) Destructor calling order in C++ is reverse order of the constructor calling order. So first derived class object get destroy and then base class object.
2) No.
In the code that you are giving, you are indeed destroying the base class and as such i. Calling a destructor and then using the dead object is undefined behavior - it may work or it may crash.
Should i was something that is more complex that an int (for example a vector), trying to do anything with that would probably result in a crash.
If you call ~SomeClass() yourself, explicitly, the destructor function will be called. Which leaves the object (in this case, the base class part of the object) in a destroyed state.
Since the destructor is not virtual, the destructor of derived classes will not be called, but base classes of SomeClass will be destroyed too.
Trying to find out if A is really destroyed by just using the i member, is not a good test. In fact, you can't test this, since using the object results in undefined behavour. It may work, or it may not (in your case, it probably will print "i=20 j=10", but i is already destroyed).
With regards to the sample code below, why is the destructor for the base class called twice?
class Base {
public:
Base() {
std::cout << "Base::Base()" << std::endl;
}
~Base() {
std::cout << "Base::~Base()" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived::Derived()" << std::endl;
}
~Derived() {
std::cout << "Derived::~Derived()" << std::endl;
}
};
int main() {
Base a = Derived();
return EXIT_SUCCESS;
}
Here is a sample of the output when the program is run:
Base::Base()
Derived::Derived()
Derived::~Derived()
Base::~Base()
Base::~Base()
What happens is called slicing. You initialize an object of type Base with an object of type Derived. Since any object of type Derived has also an object of type Base contained (called "base-class sub-object"), there will be two Base objects and one Derived object in existance throughout the program. The Derived object (and its base-class sub-object of type Base) only exists for the time of initialization, while the remaining Base object exists until end of main.
Since there are two Base objects and one Derived object, you will also see one more Base destructors run.
A copy constructor is being used. If you want to see what is going on, instrument the copy constructor too:
Base( const Base & ) {
std::cout << "Base::Base( const Base &)" << std::endl;
}
and similarly for Derived.
Note that this has NOTHING to do with the destructors not being virtual.
When you say Derived() in main() it creates a temporary object which is then copied into object a. Hence there are two objects because of which destructor is called twice. Also, as others pointed out your base class destructor should be virtual.
Because you create a temporary of type Derived before copy-constructing a with it. So this is basically what happens:
Derived d(); // Your temporary of type Derived is created
Base a(d); // The temporary is used to call a's copy constructor
d.Derived::~Derived(); // The temporary is destroyed, calling both ~Derived and ~Base
a.Base::~Base(); // The nonvirtual destructor on a is called, so ~Base is called, but not ~Derived
So apart from the unnecessary copying at the beginning (which the compiler may optimize away), the actual error is that ~Base isn't virtual.
Edit
Oops, completely missed the slicing that takes place as litb pointed out. Read his answer instead :)
Adding in the following will make the program more clear:
Base(const Base& base){
std::cout << "Base::Base(const Base& base)" << std::endl;
}
The compiler will automatically create a copy constructor for you. By defining it yourself, (and by adding in the print) you can see that the number of constructors and destructors match
Base::Base()
Derived::Derived()
Base::Base(const Base& base)
Derived::~Derived()
Base::~Base()
Base::~Base()
You need a virtual destructor.
You have one stack variable and one temporary - total of two objects constructed - so it's logical for the destructor to be called twice.
1) A temporary object of Derived type is built (Derived::Derived() and Base::Base() are called)
2) The temp object is copied into "a"
3) The temporary object is destroyed ( Derived::~Derived() and Base::~Base() are called)
4) return EXIT_SUCCESS;
5) "a" is destroyed, so Base::~Base() is called