Sign in to follow this  
EvilNando

Why is destructor getting called

Recommended Posts

I have a custom class lets call it MyClass

so in my program I have this


class Game.h
{
MyClass my_class_instance;

void Init();
void Run();
}

class Game.cpp
{
void Game::Init()
{
my_class_instance = MyClass(constructor_params); // destructor getting called here
}

void Game::Run()
{
my_class_instance.DoSomething(); // instance still valid here
}

}

Share this post


Link to post
Share on other sites
[code]my_class_instance = MyClass(constructor_params);[/code]
First you create a temporary MyClass object with [i]MyClass(constructor_params)[/i]. Then you assign this object to my_class_instance using operator=. The temporary object will not exist after this line so the destructor is called.

Share this post


Link to post
Share on other sites
[quote name='Wooh' timestamp='1317959501' post='4869973']
[code]my_class_instance = MyClass(constructor_params);[/code]
First you create a temporary MyClass object with [i]MyClass(constructor_params)[/i]. Then you assign this object to my_class_instance using operator=. The temporary object will not exist after this line so the destructor is called.
[/quote]

Oh ok but even if I do it like this

my_class_instance(constructor_params);

the destructor gets called why?

Share this post


Link to post
Share on other sites
[quote name='EvilNando' timestamp='1317959984' post='4869976']
[quote name='Wooh' timestamp='1317959501' post='4869973']
[code]my_class_instance = MyClass(constructor_params);[/code]
First you create a temporary MyClass object with [i]MyClass(constructor_params)[/i]. Then you assign this object to my_class_instance using operator=. The temporary object will not exist after this line so the destructor is called.
[/quote]

Oh ok but even if I do it like this

my_class_instance(constructor_params);

the destructor gets called why?
[/quote]

Probably because it goes out of scope, the = operator should perform a shallow copy of the instance in your case.

Thus you basically have:

MyClass my_class_instance; (from game.h) , this creates one instance of MyClass using the default constructor and it remains valid until the Game instance is destroyed.

Then you do:

my_class_instance = MyClass(parameters); this creates a second temporary instance of MyClass, copies its values to the instance you have in the Game class and then destroys the temporary instance (Which is why the destructor gets called).

Share this post


Link to post
Share on other sites
I think that what you are doing and what you are trying to do are two different things. I believe that you are confusing dynamic and static instantiation.

If I am correct in assuming this, the best thing to do in this situation would be to use a pointer.

Changing your code, we have:

Game.h
[code]
[color=#1C2837][size=2]class Game
{
MyClass* my_class_instance;

void Init();
void Run();
};[/size][/color]
[size="2"][color="#1c2837"][/code][/color][/size]
[size="2"][color="#1c2837"]
[/color][/size]
[size="2"][color="#1c2837"]Game.cpp[/color][/size]
[size="2"][color="#1c2837"][code][/color][/size]
[color=#1C2837][size=2]void Game::Init()
{
my_class_instance = new MyClass(constructor_params);
}

void Game::Run()
{
my_class_instance->DoSomething();
}[/size][/color]
[size="2"][color="#1c2837"][/code][/color][/size]

Share this post


Link to post
Share on other sites
Think of it this way: A class initialises all of its members when its constructor is called - and then it runs the constructor body.
So if you have
[source lang="cpp"]
class Game
{
MyClass my_class_instance;
void Init() { my_class_instance = MyClass(params); }
}
[/source]

Game will:
1) create my_class_instance() using the () constructor.
2) at Init(), create a temporary MyClass(params), copy it into my_class_instance using the = operator, then delete it.

Consider instead, if you have a constructor:
[source lang="cpp"]
class Game
{
MyClass my_class_instance;
Game(params) : my_class_instance(params) { }
}

[/source]

then my_class_instance will be constructed using the (params) constructor. This is important, since the following code does not do the same thing, but is instead equivalent to the first version:

[source lang="cpp"]
class Game
{
MyClass my_class_instance;
Game(params) { my_class_instance = MyClass(params); }
}

[/source]

If you really, really want to construct the instance in Init, and in Init only, then you probably want to make it a pointer:
[source lang="cpp"]
class Game
{
MyClass *my_class_instance;
Game() : my_class_instance(NULL) { }
void Init() { my_class_instance = new MyClass(params); }
~Game() { delete my_class_instance; }
}

[/source]

Share this post


Link to post
Share on other sites
[quote name='EvilNando' timestamp='1317958590' post='4869969']
[source lang="c++"]
class Game.cpp
{
MyClass my_class_instance;
...
};

void Game::Init()
{
my_class_instance = MyClass(constructor_params); // destructor getting called here
}
[/source]
[/quote]
Variables declared like this (or like [b]my_class_instance( constructor_params )[/b]) are created on the [b]stack[/b] and get destroyed when they go out of scope. In this case, the variable's scope is the method [b]Game::Init()[/b], so at the end of the function the variable gets destroyed. If you want to keep the variable around for a while, you should use a [b]pointer[/b]. So:
[source lang="c++"]
class Game.h
{
public:
Game();
~Game();
void Init();
void Run();

private:
MyClass* my_class_instance;
}

Game::~Game()
{
delete my_class_instance;
my_class_instance = 0;
}

void Game::Init()
{
my_class_instance = new MyClass(constructor_params);
}
[/source]
By using [b]new[/b], the variable is created on the [b]heap[/b], which is a different part of memory than the stack, and it doesn't get cleaned up automatically. Note that with this method, you have to destroy the object yourself by calling [b]delete my_class_instance[/b] at some point, often from the class's destructor, as I've done above. Pointers can be tricky, and many people will tell you to avoid them when possible, and to use a smart pointer when you must use one at all. Smart pointers are well worth looking into and learning how to use.

However, I think the best thing to do in this case is to use an [b]initializer list[/b]:
[source lang="c=="]
class Game.h
{
public:
Game();
~Game();
void Run();

private:
MyClass my_class_instance;
}

Game::Game()
: my_class_instance( constructor_params )
{ }
[/source]
It's cleaner this way--my_class_instance gets created at the time the Game object is created and lasts the lifetime of its parent class, and you don't need to remember to delete it. It's not always possible to use initializer lists for all class variables, but you should prefer it whenever you can.

Share this post


Link to post
Share on other sites
In C++, when you are designing a complex class (anything that isn't [url="http://en.wikipedia.org/wiki/Plain_old_data_structure"]POD[/url]), you should ask yourself, how will I handle the [url="http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)"]Rule of Three[/url]?

The simplest answer is to make all complex classes "noncopyable" by default, and when you find that this is causing your trouble in the code, then you can decide if a copy is necessary, whether to pass a (smart) reference or decide what it would mean to copy such an object.

Marking a class as noncopyable is as simple as the following (which is essentially boost::noncopyable if you're using boost):
[code]
class noncopyable
{
protected:
noncopyable()
{
}
private:
// Note: these are deliberately private and unimplemented: do not copy instances of this class!
noncopyable(const noncopyable &);
noncopyable &operator=(const noncopyable &);
};

class Fancy : noncopyable
{
// ...
};
[/code]
When you make classes noncopyable, you can concentrate on writing the correct constructor and destructor, which is typically a lot easier than trying to duplicate state.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this