• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Alian Vesuf

C++ SDL - Deleting dynamically allocated objects

16 posts in this topic

Hello GDNet. I am studying the SDL library and while doing so i find myself in troubles back in the C++ basics. 
The question is : If you delete an object that is dynamically allocated, and then try it again does it cause problems or leaks ?

 

The issue is as follows:

I have a Sprite class which basically deals with loading sprites and drawing them onto the screen.

I have Game class with functions like Init() Draw() Update() Quit().

I dynamically create new sprites in the Game class for each image i want to draw, and then i delete objects in the Quit() function.

 

In the main game loop i experimented with some things. I attached a key event to delete specific sprite object which actually removes the

sprite from the screen and clears the allocated memory. Note that i did that in the game loop. And in the Quit function i also delete

that object. Is this ok ? It does not seem to crash the program or anything but what happens behind the scenes ?

This can be an issue when the Player kills an Enemy and i free that specific object, and then back in the Quit function i try to 
free the garbage again.

Here is some code for reference

game.cpp

 Sprite Background = new Sprite();

Game::Initialize()
{
    Background->LoadSprite("bg.bmp");
    /........../
}

Game::Loop()
{
    while(Running){
      while(PollEvent){
         if(KEY == "x"){
            delete Background;
           Background = NULL;
        }
     }
   }
}

Game::Quit()
{
    //Background once deleted and now again ?
    delete Background;
}
0

Share this post


Link to post
Share on other sites

If you try to call delete on a NULL pointer, it will be ignored.

There's no necessity of a null check like:

if (pointer)
    delete pointer;

Even less:

delete pointer; //Free allocated memory.
pointer = NULL;
delete pointer; //Just to make sure.

That second delete in your code is doing nothing, but it detracts from your code's readability, potentially making it confuse to anyone reading it (even you).

Even if it does no harm directly, it is doing no good either, and I would advise against this.

Always prefer to make clear code and it will make your life way easier when a nasty bug appear!

Edited by dejaime
2

Share this post


Link to post
Share on other sites

I am confused here. Basically i delete all objects in the Quit function. But if an enemy object gets killed in the main loop where game logic happens i free the texture and delete the object. Also you never know if the enemy will be killed in the main loop so you need to take care of it in the end function also.

 

So the best practice is to assign NULL to pointers that don't get to play anymore ( if they ) and delete them in the end just to make sure or if they survived game logic ?

Edited by aliasc
0

Share this post


Link to post
Share on other sites
Don't do that.
 
Double-delete is a very serious bug.

Sorry about that, fixed the code with what I originally meant to write.

I'm just too used to my overloaded delete that nullifies it for me; my bad.

 

 

@ Back on topic,

Under normal circumstances, you delete any objects when you know for sure they won't be reused.
Sometimes that happens during the gameplay, and sometimes at the end.
 
Still, you can avoid going around calling delete, by, for example, calling a function to make unused objects delete themselves.
 

#include <algorithms>
#include <vector>

bool exit;

class AwesomeGameObj {
    private:
        static std::vector<AwesomeGameObj*> MasterVector;
        bool isUseless;
    public:
        AwesomeGameObj () {
            /*Initialize everything*/
            isUseless = false;
            MasterVector.pushback(this);
        }
        
        ~AwesomeGameObj () {
            /*Do the cleanup*/
            MasterVector.erase(/*this object*/);
        }
        
        void de_init () {
            while ( !MasterVector.empty() ) {
                delete MasterVector.back();
                MasterVector.pop_back();
            }
        }
        
        bool useless () const {return isUseless;}
        
        static void clean_up () {
            for (/*every object in MasterVector*/)
                if (object->useless()) {
                    vec.erase(/*object*/);
                    delete /*object*/;
                }
        }
        
        static void clean_up (std::vector<AwesomeGameObj*> vec*) {
            for (/*every object in vec*/)
                if ( object->useless() ) {
                    vec->erase(/*object*/);
                    delete /*object*/;
                }
        }
        
        void update () {
            /*do anything it needs to do*/
            if (/*something very very sad happened*/)
                isUseless = true;
        }

};

void quit () {
    AwesomeGameObj::de_init();
    /*do it for any other object types that needs this clean up here*/
}

void init_all () {
    /*init anything*/
}

int main()
{
    //Game Objects in general
    std::vector<AwesomeGameObj*> gameObjects; 
    
    //Fix don't-delete-while-running game objects.
    std::vector<AwesomeGameObj*> miscUseObjects;
    
    init_all();
    
    //Initialize some special objects
    while (/*needs misc objects*/)
        miscUseObjects.push_back (new AwesomeGameObj);
    
    //Main loop
    do {
        while (/*needs new objects*/) {
            gameObjects.push_back (new AwesomeGameObj);
        }
        
        for (/*all gameObjects and miscUseObjects*/) {
            object.update();
        }
        
        if (/*you want to free memory*/)
            AwesomeGameObj::clean_up(gameObjects);
        
    } while (!exit);
    
    //We'll most probably have objects remaining;
    quit();
    
    return 0;
}

As you can see in this example pseudo code, I avoid to call delete on the main and quit functions. I do this by passing on the responsibility of doing so to the object's own class, and all I have to do is tell it to clean up its memory, despite how many objects I need to free and where they are, where they were allocated or anything. This way my main and end functions doesn't have to worry about remaining objects nor freed objects.

Edited by dejaime
1

Share this post


Link to post
Share on other sites


Second: You usually use an dynamic array (std::vector) to keep track of game objects.


Do you mean for specific types of objects. How would you store all of game objects in a dynamic array when they all are of different types.
You can of course std::vector<Sprite> spriteList. Also can you check if specific object exists in the list before deletion ?

Anyway this : 
int* a = new int;
delete a;
a = nullptr;
delete a; // <-- OK

means after delete pointer assign nullptr and then delete the null pointer which is safe and so it solves my problem! Thanks !

0

Share this post


Link to post
Share on other sites

I may have missed something, but is there a reason to keep the Background object as a pointer?


Then you don't have much control over memory. I could call the Unload function to drop a texture but the object and its data will still be there till 
out of scope or game end, which is pretty much a waste. Why remain the object till game loop ends when it is no useless anymore (sprite without texture in this case) and you could drop it from memory.

std:make_unique is awesome, although i use MinGW not Visual Studio's compiler.
I guess i will stick with 

int* a = new int;
delete a;
a = nullptr;
delete a; // <-- OK

if its totally safe.

 

 

 


bool useless () const {return isUseless;}

static void clean_up () {
for (/*every object in MasterVector*/)
if (object->useless()) {
vec.erase(/*object*/);
delete /*object*/;
}
}

static void clean_up (std::vector vec*) {
for (/*every object in vec*/)
if ( object->useless() ) {
vec->erase(/*object*/);
delete /*object*/;
}
}

void update () {
/*do anything it needs to do*/
if (/*something very very sad happened*/)
isUseless = true;
}


dejaime im i missing a point or you i dont know. I dont understand your solution pretty much.
You keep objects in dynamic array and check for their state if they are not useless then you delete them.
This isUseless is only checked in clean_up() function
As far as i understood you remove the object from the array when it is useless but you are not deleting it till cleanup, which pretty much can be called within game loop or end game. And again if you call clean_up() in game loop you need to make sure to call it in the end game if object is not useless, which again leads back to my problem.
But if you only assign isUseless in the game logic and do clean_up() in the end it basically means that the object with its data except the texture will still remain in memory till endgame. I want to free things from memory since they are not usable anymore. Probably i miss something i don't know and your solution may be efficient enough, but it does not seem to be structured well as you know that in game you don't deal with specific objects only. So keeping structured attaching same logic for everything helps readability and not getting frustrated when things go complex.

Edited by aliasc
0

Share this post


Link to post
Share on other sites

MinGW 4.7 onward (if i remember the version correctly) supports most of C++11, if not all of it, and unique_ptr is part of that.

 

His solution avoids deleting stuff in the middle of the game loop. If you do a lot of deleting and allocating within the main loop, you're going to run into hiccups in your framerate when you kill a lot of stuff at the same time. Also, iterating over a container of objects and deleting them at the same time is a bad idea and just invites bugs and/or crashes.

1

Share this post


Link to post
Share on other sites

MinGW 4.7 onward (if i remember the version correctly) supports most of C++11, if not all of it, and unique_ptr is part of that.


Yes, however std::make_unique requires C++14. If and how much C++14 is supported will depend on what version of MinGW is used. Of course it can't hurt to specify -std=c++14 instead of -std=c++11 and just try it out.
1

Share this post


Link to post
Share on other sites

What i like to do is have a class be the manager of actors (an entity in the game).

This class is in charge of everything related to actors like maintaining a list of them, checking if they are alive, updating them and even drawing them (well, the calss check if it need to be drawn, then call another class to draw). I keep a std::vector of all actors.

 

When an actor is killed, i do not delete it yet, i only set the flag for it to be deleted on the next frame.

 

In my game loop is a function i call "MaintainActiveList". What this do is loop throught all actors and check if they are alive and if they are on screen.

 

If the dead flag is set, i delete them and remove them from the array.

 

When the program quit (or change map etx...) i loop through all remaining actors and delete them.

 

The advantage this did to my game is actors are only updated and drawn if they are active and alive.

 

void CActorManager::MaintainActiveList()
{
	mActiveActors.clear();
	for (std::vector<IActor*>::iterator i = mActors.begin(); i != mActors.end();)
	{
		if((*i)->IsState(STATE_DEAD))
                {    
                    IActor * actor = (*i);
                    mActors.erase(i);

                    delete actor;
                    actor = NULL;
                }
		else if ((*i)->IsActive() )
		{
			mActiveActors.push_back((*i));
			 ++i;
		}
		else
			 ++i;
	}
}

Also, for the texture: The same thing for the actor Manager can be done for texture. If you use the same texture for different actor (Let's say you have a lot of clone) there is no need to have the same texture allocated in memory more than once. A texture manager can solve this problem. The actors can then store a pointer to the texture. Be warned that you then can only delete the texture if all actor using it are gone.

0

Share this post


Link to post
Share on other sites

 Sprite Background = new Sprite();

'Background' here isn't a pointer (unless Sprite is typedef'd as a pointer), so calling "new" here shouldn't compile.
But 'Background' shouldn't be global anyway, it should probably be a member variable of 'Game'.
And unless required by your API, 'Background' shouldn't be a pointer at all. Just a regular variable (Sprite should handle it's own dynamic memory internally).

In my opinion a programmer should, by default, use memory whose lifetime is automatically managed:
int x = 0;
Sprite sprite;
 
int *ptrX = &x;
Sprite &spriteRef = sprite;
 
struct MyStruct
{
     Sprite background;
     std::vector<Sprite> arrayOfSprites;
};
If I must use manually-managed variables, then I prefer smart pointers.
C++11's smart pointers include: std::shared_ptr, std::weak_ptr, and std::unique_ptr. Each have different uses for different situations. Your compiler will need C++11 enabled to use.
(Don't use std::auto_ptr which is deprecated and no longer recommended for use)
std::shared_ptr<Sprite> sprite = std::make_shared<Sprite>("path/to/image.png");

In very rare occasions, I need to actually manually micro-manage your memory. In those situations, then I use new and delete. In normal hobbyist code, this shouldn't occur too often. It occurs more often when certain APIs enforce the use of new and delete, or when maintaining older code bases or using outdated compilers. Edited by Servant of the Lord
2

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  
Followers 0