Destruction order of class data members? - c++

Imagine a class like this:
class foo {
public:
foo() : _bar{new bar}, _baz{new baz} {}
private:
unique_ptr<bar> _bar;
unique_ptr<baz> _baz;
};
So whenever an instance of foo gets destructed, then in what order will the data members of it be destroyed, if that's defined behavior at all?
Let's say that _baz does depend on the existance of _bar, maybe it uses some resource that _bar owns (let's assume it knows about the _bar object, even though the constructor doesn't reflect this).
So in this case, if _bar gets destructed first (when its time to destruct foo), then _baz could potentially try to access some resource which has been freed by _bar's destructor.
An obvious solution is to implement a destructor in foo, which manually frees _baz and _bar in the right order, but what if there's no destructor implemented? Is there a default behavior that defines the destruction order of data members?

The order of destruction of data members is the reverse of their order of declaration, the same way as variables declared within a scope:
{
// a, b constructed in that order
bar a;
baz b;
} // b, a destroyed in that order

Related

C++: What happens to a dynamically allocated object created as an argument in a constructor call?

Say I am making a new object of class Foo, which takes an object of class Bar as a constructor argument. If I created this object in this manner:
Foo myObj(new Bar());
what happens in this case to the new object? I've seen code similar to this example (with no name for the new object created as an argument). Where would I put my delete call to free the memory taken by the Bar object?
It depends, if it is allocated like in your example, hopefully your Foo class is managing it, otherwise the Bar will be leaked
class Foo
{
public:
Foo(Bar* bar) : m_bar{bar} {}
~Foo() { delete m_bar; }
private:
Bar* m_bar;
};
Or if you have access to C++11 you could have a std::unique_ptr
class Foo
{
public:
Foo(Bar* bar) : m_bar{bar} {}
private:
std::unique_ptr<Bar> m_bar;
};
new Bar() yields a pointer which becomes the constructor argument of Foo(Bar*) (or, if Bar is a class derived from Base the constructor may be Foo(Base*).
The corresponding constructor of Foo should deal with the resource as it is otherwise leaked.
It stays in the program. If you have too many of these loose ends or if its repeated too often, the program will become a memory hog because it never returns the memory it borrows.
Yes, this is dangerous for loose ends. This is why people tend to use primitives like std::unique_ptr<Type> that manage themselves and automatically destruct as it goes out of scope and can also transfer ownership in natural ways.
Programming in that delete myObj; is often forgotten, so people have devised ways to get around it.
If you have a manual new in a constructor, put the delete in the destructor. This concept is related to RAII: Resource Acquisition Is Initialization

Object created on the heap is not global?

I read a book S. Lippman "inside c++ object model", is there such code
class Foo { public: int val; Foo *pnext; };
void foo_bar()
{
// Oops: program needs bar's members zeroed out
Foo bar;
Foo* baz = new Foo(); // this line i added myself
if ( bar.val || bar.pnext )
// ... do something
// ...
}
and it says that
"A default constructor is not synthesized for this code fragment.
Global objects are guaranteed to have their associated memory "zeroed out" at program start-up. Local objects
allocated on the program stack and heap objects allocated on the free-store do not have their associated memory
zeroed out; rather, the memory retains the arbitrary bit pattern of its previous use."
In this code the baz object was created on the heap, and according to what has been said above this object is not global and it will not be called the default constructor. I understand correctly ?
The parentheses in new Foo() specify value initialisation; this basically means that each member is zero-initialised. If instead you said new Foo, then the members would be left uninitialised, as they are for your automatic variable.
Unfortunately, to value-initialise the automatic variable, you can't write Foo bar(), since that declares a function. You'll need
Foo bar{}; // C++11
Foo bar = Foo(); // Historical C++
When you do this:
Foo* baz = new Foo();
you are dynamically allocating a Foo instance and value-initializing it. For PODs, this means the members get zero-initialized. If you had said this (assuming non-global context):
Foo* baz = new Foo;
then the Foo instance would be default initialized, which would mean no initialization of its members is performed, since they are PODs.
This also applies to automatic storage instances:
Foo f0; // default initializaiton: members not zeroed out.
Foo f1 = Foo(); // value initialization: members zeroed out.
Foo f2{}; // C++11 value initialization: members zeroed out.
Foo f3(); // Ooops! Function declaration. Something completely different.
If a class have no default constructor (and no other constructor), the compiler will create one for you. It has to, or you would not be able to create instances of the class. However, the generated default constructor will not do anything.
What adding the empty set of parentheses in new Foo() does, is to value initialize the allocated object, which means the members gets initialized to their "default" values, which is zero for integer and floating point values, and nullptr for pointers.

C++ need clarification about destructors and scope

I have a problem, and I'm pretty sure I know the cause of it. I'd just like some clarification. I have a class that contains other classes, but I'll limit my example to two classes for simplicity.
Class A contains class B. In class A's constructor, it initializes class B by calling B's constructor. At the end of class A's constructor, class B's destructor gets called, which wasn't the behavior I was expecting. Here's an example...
a.h
#include "b.h"
class a {
public:
b classB;
a(int someParam);
};
a.cpp
#include "a.h"
//Class A's constructor
a::a(int someParam) {
//Set class B by calling it's constructor
classB = b(someParam);
//Now class B's destructor gets called when exiting A's constructor...
}
I know that if you declare a variable without using "new", it gets destroyed when it leaves the current scope. But I always thought that applied to the variable's scope, and not to the scope at which you assign a value to it. That is the problem, right? If it is, there's nothing wrong with doing classB = *new b(someParam); is there? Or should I just use pointers instead?
In this line:
classB = b(someParam);
The expression b(someParam) creates a temporary, nameless b object, which is then asssigned to the member object, classB. It is the destructor of this nameless temporary which is called, not the destructor of your member object. If you want avoid the creation of this temporary, and instead directly initialize your member object with the appropriate constructor, use the initialization list:
a::a(int someParam)
:classB(someParam)
{}
And this:
classB = *new b(someParam);
Is an instant memory leak. You're allocating an object on the free store, copy assigning from it to classB, and losing the pointer.

Base class's destructor called without destroying the base class!

#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).

When are member data constructors called?

I have a global member data object, defined in a header (for class MyMainObj) like this.
class MyMainObj
{
MyDataObj obj;
}
MyDataObj has a default constructor.
When is the constructor for MyDataObj called?
Is it called as part of the creation of MyMainObj?
MyDataObj in this case is not a member of MyMainObj, it's a local variable.
But, constructors for data members are called in your class's constructor. The default constructor for every member is called before execution reaches the first line in the constructor, unless you explicitly specify a constructor using an initializer list, in which case that constructor is called instead.
With that code, obj isn't a member of MyMainObj -- it's simply a local object inside that constructor. As such, it'll only be constructed when/if that constructor is invoked.
Concerning your code, you have a function with a variable inside. Upon entering the function, you will run to the line of code that declares the variable, and the constructor will be run then.
But you say "creation of MyMainObj". It's a function, it can only be called, not created.
This is all concerning the title question, "when are members constructed?" This would apply if MyMainObj was a class and not a function.
Your member objects are constructed in the order of which they appear in the class declaration. All objects are full constructed upon entering the constructor. (But this does not include the class itself!)
That is to say, by the time the class enters its constructor, all the members have finished their constructor.
Objects are destructed in reverse order, in the destructor (after the destructor is run).
In a pseudo-diagram:
MyClass
Member1
Member2
Member3
Construction:
Member1
Member2
Member3
MyClass
Destruction:
MyClass
Member3
Member2
Member1
You can manually call the members constructor using an initialization list:
class foo
{
public:
foo(void) : i(0) // construct i with 0.
{
}
int i;
};
There are various question on SO about initialization lists. Initialization list order, Copy-construction initialization list, and more.
Yes, the constructor would be called whenever a MyMainObj instance is created.
I'm a bit confused by the "global member" terminology - the way you've declared that object it would be a local variable inside the constructor. Am I missing something here?
Yes, as other stated the member will be created on the owner class creation, on construction (be it generated by the compiler or with a provided constructor).
The order of creation will be the same as how your members apear in the class declaration. For example :
class MyType
{
Thing a;
Thing b;
Thing d;
Thing c;
};
Whatever constructor is used, whatever the order in a initialization list, the members will be constructed in this order : a, b, d, c. Once it's all done, the constructor code will be executed (if it exists) and only then your whole object will be constructed.
Upon entering an object constructor, memory has already been allocated for it. Then the execution order is as follows:
Base class constructor, if any, as specified in the initialisation list; if not specified, the default constructor is used.
The constructors for the member data, as specified in the initalisation list (default if not specified), in the order they are declared in the class definition. The order in which they are specified in the initialisation list is irrelevant.
The constructor body.
In the example set in the question, the first thing that would be executed upon entering the default constructor of MyMainObj would be the default constructor of MyDataObj to construct the member data obj.
Given a class A:
class A {
MyDataObj obj;
}
If you don't write the constructor for A, the compiler will create one for you, which will create obj as part of constructing A (and destroy obj as part of destroying A.
If you do write a constructor for A, then obj will be created before your constructor runs, although you can reassign it:
class A {
MyDataObj obj;
public:
A() { } // obj created, but the value may or may not be predictable
}
class AA {
MyDataObj obj;
public:
AA()
{
obj = MyDataObj(5);
}
}
class AAA {
MyDataObj obj;
public:
AAA() : obj(5) { } // member initializer list, my preferred method
}
With the third option, the data objects are created before the member initializer list runs, and the values are assigned in the order they are declared in AAA, NOT the order they are listed in the member initializer list.
UPDATE: There is a difference between creation and initialization. Space for the data members (and the base classes, and the data members for the base classes) is always set aside -- which I would call "creation." However, that doesn't mean a useful value is stored in that memory. There are separate rules for whether an object is default initialized, which depend on the type of the data member (primitive, POD, non-POD) and, IIRC, the storage class of the main object (local, static, global). The easiest way to avoid surprises in this area is to simply make sure you explicitly initialize everything.