• Advertisement
Sign in to follow this  

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.

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


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

Maybe take a look at this article:
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 SPRITES
Window window;
Sprite hud;

//Tiles
Sprite grass;
Sprite bush;

//LABELS
Label scoreLabel;
Label highscoreLabel;
Label lengthLabel;

//OTHER
TTF_Font* font;

//VARIABLES
int score;
int highscore;
int length;

char field[FIELD_WIDTH][FIELD_HEIGHT];

//FUNCTIONS
void Init();
void Game();
void Quit();
void Draw();
void Reset();

//MAIN
int main(int argc, char *argv[])
{
Init();
Game();
Quit();
return 0;
}

//Load and Initialise
void 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 Cleanup
void Quit()
{
TTF_CloseFont(font);
}

//Draw Graphics
void 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 Game
void Game()
{
Reset();
while(!window.Closed() && !window.KeyHit(SDLK_ESCAPE))
{
Draw();
}
}

//Reset Statistics
void 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


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

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Yes. The order of destruction is always the reverse of the order of construction.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rainault
Is 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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement