# Destructors

This topic is 4163 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I just want to clear something up. So, if I have a class with dynamically allocated memory, and it has a destructor that frees that memory, and I have a program that uses it like this: int main() { Class myClass; return 0; } It will call the destructor when it goes out of scope? I don't have to call it manually?

##### Share on other sites
Yes it will automatically be called.
You can test this by putting a breakpoint inside the destructor.

Edit: Yes, I did mean destructor

[Edited by - Deventer on August 13, 2006 12:53:04 AM]

##### Share on other sites
You mean destructor?

Thanks! Then I don't have to manually call all my "Destroy" methods for my wrapper classes, lol.

##### Share on other sites
If you dynamically allocate, i.e. like the following sample:

class A{public:  A();  ~A();};int main(){  A* a = new A();  delete a; // <-- if you don't have this the destructor won't be called}

you have to make sure you have a call to delete as well to match every new call you do, unless dealing with an array where you want to call delete[]

##### Share on other sites
If an object is statically allocated, its destructor is called when it goes out of scope. If an object is dynamically allocated, its destructor is called when you use delete on the appropriate pointer.

Please note this important rule of thumb: when a class implements a custom destructor, copy constructor or assignment operator, it usually needs all three of them.

A typical example of why it is so is when your class contains a pointer and a destructor that deletes it. With the default copy operation, the pointer itself is simply copied, which means that you now have two objects that share the same pointer. When the first object is destroyed, the memory is released. The second object is then left with a dangling pointer which will at the very least cause problem upon destruction of that second object. Similarly, the default assignment will overwrite the pointer in the object you are assigning to, causing a memory leak, and leave you in the same situation as with copy construction, with aliased pointers. You thus need to either make sure copying is done properly, either by reference counting the pointer, or by making a deep copy -- depending on the semantics you wish to implement, or purely and simply disable such copying, by declaring the copy constructor and assignment operator private and not providing an implementation, which will cause a compile-time error if a copy is attempted.

##### Share on other sites
Quote:
 It will call the destructor when it goes out of scope? I don't have to call it manually?

You can test the behaviour like this:
#include	<string>#include	<iostream>class Foo{public:	Foo() : m_name()	{		std::cout << "Default constructor called." << std::endl;	}	Foo(const std::string & name) : m_name(name)	{		std::cout << "Constructor for " << m_name << " called." << std::endl;	}	~Foo()	{		std::cout << "Destructor for " << m_name << " called." << std::endl;	}	void SetName (const std::string & name)	{		m_name = name;	}private:	std::string m_name;};int main (){// Dynamic	Foo * pf = new Foo("DynamicFoo");	delete pf;// Dynamic Array	Foo * pfa = new Foo [2];	pfa[0].SetName("DynamicFooArray_0");	pfa[1].SetName("DynamicFooArray_1");	delete [] pfa;// Static	Foo sf("StaticFoo");// Static Array	Foo sfa [2];	sfa[0].SetName("StaticFooArray_0");	sfa[1].SetName("StaticFooArray_1");	return 0;}

##### Share on other sites
Thanks everyone! I've got it now.

##### Share on other sites
Just wondering why noone mentioned std::auto_ptr in this context.

http://www.gotw.ca/publications/using_auto_ptr_effectively.htm

Instead of storing a raw pointer to some data inside your instance, you may store an auto_ptr in your instance wrapping that data pointer. This way the data will be deleted automatically when the instance containing the auto_ptr is deleted.

##### Share on other sites
Actually, this all brings up another of my questions. Why use "New"? It seems like you can always just say "Class myClass;" rather than "Class myClass = new Class".

##### Share on other sites
First off, "Class myClass = new Class;" will not compile (myClass needs to be a Class*, not a Class).

Now. There are a lot of reasons for using dynamic allocation.

For one, static allocations have a fixed scope and lifetime (e.g., if it is allocated on the stack within a certain scope, it lives only for that scope; if you want it to live longer you must move it to an external scope (potentially ugly from a design point of view and may involve the use of globals, which introduce their own problems) or dynamically allocate it.

You may need to allocate a number of the objects, and you don't know that number at compile time, so runtime dynamic allocation (directly, or indirectly via std::vector or similar) is required.

Without dynamic allocation, certain data stuctures are anywhere from amazingly difficult to downright impossible to implement.

The object in question might be very, very large and your program might not neccessarly use the object during its runtime, in which static allocation consumes memory you don't need to be consuming.

Stack space is limited, if an object is too big you may basically have to allocate it on the heap.

And so on. There are plenty more. Note that it's of course generally preferable to use a class that manages your memory for you -- an auto_ptr, shared_ptr, vector, et cetera as appropriate, but that's not really the scope of this thread.

##### Share on other sites
Hold on, I've run into an interesting problem. I have several classes that I made with SDL, for Windows, Sprites, and Labels. Before I added the destructors, I had a Destroy function that you had to call manually. It all worked then, but now, it crashes if I try to draw a sprite onto a window. I've tested, if I take out the destructor and replace it with a Destroy function, it works, but it seems as thoug h the destructor is being called too early. Here is the code:
//INCLUDE FILES#include <stdio.h>#include <stdlib.h>#include <string.h>#include <SDL/SDL.h>#include <windows.h>#include <vector>#include "Uph.h"//PRE-PROCESSOR DEFINES#define SCREEN_WIDTH 800#define SCREEN_HEIGHT 600#define SCREEN_DEPTH 16#define WINDOW_TITLE "Cobra 2.0"#define GRASS 0#define BUSH 1#define BLOCK_SIZE 40#define FIELD_WIDTH 20#define FIELD_HEIGHT 14//WINDOWS AND SPRITESWindow window;Sprite hud;//TilesSprite grass;Sprite bush;//LABELSLabel scoreLabel;Label highscoreLabel;Label lengthLabel;//OTHERTTF_Font* font;//VARIABLESint score;int highscore;int length;char field[FIELD_WIDTH][FIELD_HEIGHT];//FUNCTIONSvoid Init();void Game();void Quit();void Draw();void Reset();//MAINint main(int argc, char *argv[]){    Init();    Game();    Quit();    return 0;}//Load and Initialisevoid Init(){    //Create The Window    window.MakeWindow(WINDOW_TITLE, WINDOW_TITLE, CURSOR_ON, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH);    //Load The HUD Background    hud.Load("images/hud.bmp");    hud.SetX(0);    hud.SetY(560);    //Label For Displaying Score    scoreLabel.SetX(5);    scoreLabel.SetY(570);    //Label For Displaying Highscore    highscoreLabel.SetX(200);    highscoreLabel.SetY(570);    //Label For Displaying Length    lengthLabel.SetX(400);    lengthLabel.SetY(570);    //Grass Tile    grass.Load("images/tiles/grass.bmp");    //Bush Tile    bush.Load("images/tiles/bush.bmp");    //Load Arbeka Font    font = TTF_OpenFont("ARBEKA.TTF", 20);}//Quit and Cleanupvoid Quit(){    TTF_CloseFont(font);}//Draw Graphicsvoid Draw(){    window.Clear(255, 255, 255); //Clear The Window    //Draw HUD    hud.Draw(hud); //Draw The HUD    hud.Draw(window);    scoreLabel.SetText("Score: " + UphGE::IntToString(score)); //Set Score Text    scoreLabel.Draw(window, font, 255, 255, 255); //Draw Score Text    highscoreLabel.SetText("Highscore: " + UphGE::IntToString(highscore)); //Set Highscore Text    highscoreLabel.Draw(window, font, 255, 255, 255); //Draw Highscore Text    lengthLabel.SetText("Snake Length: " + UphGE::IntToString(length)); //Set Length Text    lengthLabel.Draw(window, font, 255, 255, 255); //Draw Length Text    //Draw Field    for(int x = 0; x < FIELD_WIDTH; x++)    {        for(int y = 0; y < FIELD_HEIGHT; y++)        {            switch(field[x][y])            {                case GRASS:                grass.SetX(BLOCK_SIZE*x);                grass.SetY(BLOCK_SIZE*y);                grass.Draw(window);                break;                case BUSH:                bush.SetX(BLOCK_SIZE*x);                bush.SetY(BLOCK_SIZE*y);                bush.Draw(window);                break;            }        }    }    window.Show(); //Flip The Window Buffer To Display}//Start The Gamevoid Game(){    Reset();    while(!window.Closed() && !window.KeyHit(SDLK_ESCAPE))    {        Draw();    }}//Reset Statisticsvoid Reset(){    //Reset Scores    score = 0;    highscore = 0;    length = 0;    //Reset Field Values    for(int x = 0; x < 20; x++)    {        for(int y = 0; y < 14; y++)        {            field[x][y] = BUSH;        }    }}

If I take out everything but "window.Clear..." and "window.Show()", it works fine. I have no idea what's going on. In the destructor, all that happens is the buffer image gets freed. Anyone have any ideas?

##### Share on other sites
Got It! I had SDL_Quit() and TTF_Quit() in the window destructor. I guess that can't go in there.

##### Share on other sites
Yeah, probably not. Though I don't know much about SDL or whatever library "TTF_Quit()" belongs to, I note that you have many global objects. The constructors for said objects execute prior to main(), and the destructors after main() has exited. This can often cause havoc in many subtle ways (also, dynamic allocation of said global objects could be used to more tightly regulate the lifetime of said objects, as I mentioned above; although it'd be better to focus on removing the globals instead, but that's another issue).

##### Share on other sites
Sorry to bring back this old post. Although I'm pretty sure about the answer, I just want to check:

Class myClass; //If I create an object here...int main(){   return 0;}//It's destructor will be called even though I've already "returned" from main?

##### Share on other sites
If it was created it will be destroyed. However, since your object was never used, it may not be created in the first place.

##### Share on other sites
It was just an example, I would normally use it of course. But that answers my question.

##### Share on other sites
If you have several global objects, is there an order in which their destructors are called at the end of the program? I did some testing and it seems that the first object declared is always the last one to have it's destructors called. Is it just a coincidence or is this always the case?

##### Share on other sites
Within a single translation unit, the order of construction is well-defined (thus, so is the order of destruction). Across translation units, it is not.

##### Share on other sites
Yes. The order of destruction is always the reverse of the order of construction.

##### Share on other sites
Is that because of the FIFO nature of the stack?

##### Share on other sites
It has nothing to do with the stack; statically-allocated objects such as globals are not stored on the stack.

##### Share on other sites
Quote:
 Original post by RainaultIs that because of the FIFO nature of the stack?

No. It's also true of variables that are statically allocated (i.e. globals) or variables that got constructed in the same scope. Destroying variables in reverse order is the simplest way to take care of any dependence issues. If B depends on A, B must be created after A and destroyed before it.