Sign in to follow this  

Having problems deleting an object.

This topic is 2044 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

Hello all,

Long time reader, 4th time poster. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

So I am getting back into programming after an 8 month break and am setting myself small tasks in order to cement my understanding of things that I have forgotten/didn't fully understand in the first place.

This latest task is memory deallocation, ideally creating one or two robust (enough for now), methods that can delete and remove an object from a game. Objects such as a pick-up or an enemy, upon collision with the player character. Before I would just create flags that stopped said objects ability to render/increase player score.

I understand the concept that in order to do this, without the program crashing, I need to remove every reference of the object to be deleted. This includes deleting its associated assets such as sprite images.

Before this current mini-project I made two small main method only programs, the basic outcome of both was that after creating and deleting a number of pointer objects, when reassigning near the end, the first memory address to be allocated would be reused after it was first freed. For example (please bear with me on the arbitrary numbers to represent memory addresses):

Object 1 is created and stored at memory address 2000,
Object 2 is not created.
Object 1 is deleted.
Object 2 is created and stored at 2000.
Object 1 is re-instantiated and stored at 2001.

The problem that I have is that in my new program, which is an evolution of the previous two, the outcome is not as I have set out above:

Object 1 is created and stored at memory address 2000,
Object 2 is created and stored at memory address 2001.
Object 2 is deleted and its pointer set to NULL.
Object 2 is re-created and stored at 2002.

Can anyone explain to me why this might be happening, I have used the debugger and set a number of watches. I also create a third pointer to save the memory address location of Object 2, just to see what happens to that memory address later in the program.

My source code is copy-pasted below. If more information is required, please feel free to ask as I am new to posting code and am unsure how much I need to include.

Thank you very much for your time in reading this, and your feedback is very much appreciated.

Stitchs.

P.S. I am using Allegro v4, MS Visual Studio 2010 and C++

P.P.S. There are some references to cin.get(), these were from when the program used the console window, please disregard.


[CODE]
#include <allegro.h>
#include <iostream>
#include <string>
#include <vector>


using namespace std;

const unsigned char PROGRAM_EXIT_SUCCESSFUL = 0; // Constant value that indicates main() can stop execution without error
const unsigned char PROGRAM_EXIT_UNSUCCESSFUL = -1; // Constant value that indicates main() should stop execution because of error

// Data structure to represent a Character type
struct character_t{
// Holds 4 attributes
int x, y; // X and Y coordinates
string name; // Name of character
BITMAP *image; // Image to represent character on-screen
void render(){ draw_sprite(screen, image, x, y); };
} *hero, *zero; // Initialises a character variable: 'hero'

// Initialise characters
void character_init(){
hero = new character_t();
hero->x = 20, hero->y = 20, hero->name = "Hero", hero->image = load_bitmap("smiley.bmp", NULL);
zero = new character_t();
zero->x = 80, zero->y = 80, zero->name = "Zero", zero->image = load_bitmap("sadley.bmp", NULL);
return;
}

// Function prototype for deleting a single character from a vector.
// Takes 2 parameters. One that represents a reference to character vector, the
// second representing the position at which that character is stored
// in the vector.
void delete_character_from_vector(vector<character_t*> &char_v, int &vector_position);


int main()
{
// Check to see if the Allegro library initialised
if(allegro_init() != 0){
// If not, display message to user and return 1, indicating program to exit
cout << "Allegro not initialised." << endl;
cin.get();
return PROGRAM_EXIT_UNSUCCESSFUL;
}

// Check to see if keyboard installed successfully
if(install_keyboard() != 0){
// If not, display message to user and return 1, indicating program to exit
cout << "Keyboard not installed." << endl;
cin.get();
return PROGRAM_EXIT_UNSUCCESSFUL;
}


set_color_depth(32);

// Check to see if a Graphics mode can be set under the above color depth
if(set_gfx_mode(GFX_AUTODETECT_WINDOWED,1024,768,0,0) != 0){
// If not then display an error message to the user
// and wait for a key input, before indicating main()
// to exit.
cout << "Allegro failed to set Graphics mode." << endl;
//cin.get();
readkey(); //cin.get() does not function as Allegro window has focus.
return PROGRAM_EXIT_UNSUCCESSFUL;
}


clear_to_color(screen,makecol(0,0,0));

character_init();


// Creates a vector to store characters in
vector<character_t*> characters;
// and load the characters.
characters.push_back(hero);
characters.push_back(zero);

// Character pointer to point to the original address of zero
character_t *store_zero = zero;


// Integer to store the address of zero, one to store the new memory address that will be assigned later.
int zero_orig_memadd = (int)&zero, zero_new_memadd;

bool value = true; // Boolean value to fire the delete process
int char_to_del = 1; // Integer variable to pass into the second argument of delete_character_from vector


//acquire_screen();
while(!key[KEY_ESC]){

// Use the enter key to start the delete event
if(key[KEY_ENTER]) value = false;
// Use a Boolean to keep track of deletion, so that once the character[1] is deleted, it can not be triggered again
if(value == false){
delete_character_from_vector(characters, char_to_del);
zero = NULL; // specify character 'zero' now, just for testing purposes
// Clears the colour of the screen so that the hero and zero images get overwritten.
clear_to_color(screen, makecol(0,0,0));
// Instantiate the 'zero' pointer with a new object, to check that the memory block being pointed to is reassigned correctly.
zero = new character_t(), zero->x = zero->y = rand() % screen->h - 32, zero->name = "nero", zero->image = load_bitmap("sadley.bmp", NULL);
characters.push_back(zero); // push zero back into the vector
zero_new_memadd = (int)&zero; // store the new memory address of zero
value = true; // reset 'value' so that this 'if' clause cannot be accessed without ENTER
}

// ============================ //
// RENDER PHASE //
// ============================ //
// Check to see if the character vector is not empty, if it is empty, then the pointer would also have been deleted
if(!characters.empty()){
// Loop through the vector
for(unsigned int i = 0; i < characters.size(); i++){
characters[i]->render();
}
}
rest(50);
}
// ============================ //
// DELETE PHASE //
// ============================ //
for(unsigned int i = 0; i < characters.size(); i++){ // has to be less than, NOT <=
// Destroy the image before deleting the pointer
// referencing the area of memory containing it.
destroy_bitmap(characters[i]->image);
delete characters[i];
characters.erase(characters.begin() +i);
}
return PROGRAM_EXIT_SUCCESSFUL;
}

END_OF_MAIN();


void delete_character_from_vector(vector<character_t*> &char_v, int &vector_position)
{
if(!char_v.empty()){
// Delete the character at selected position,
destroy_bitmap(char_v[vector_position]->image);
delete char_v[vector_position];
// Set the character pointer to NULL,
char_v[vector_position] = NULL;
// If-else to check for successful deletion, otherwise return a faulty code.
if(char_v[vector_position] == NULL){
// Erase the element stored in vector.
char_v.erase(char_v.begin() + vector_position);
// Return.
return;
} else {
// Output some kind of error code to restart the deletion process?
}
}
}
[/CODE]

Share this post


Link to post
Share on other sites
When you use the "new" operator, all you're doing is asking for [i]some[/i] memory of a given size. There's no guarantee offered by the language or the memory allocation implementation itself that you'll get the results you describe.

Generally if you want really tight control over the [i]addresses[/i] of your allocations you need to write your own allocator. But the good news is that in 99% of situations that's total overkill, because you don't actually [i]need[/i] to care about the addresses.

Share this post


Link to post
Share on other sites
Thanks for the swift response. I understand what you're saying. My concern, and judgement, were lead by my first two attempts, that the address previously used would be re-used so long as something was assigned to the pointer straight after it was deleted. The concern comes that, if I cannot say for sure that this address does not get re-used as I expect, would it technically be a memory leak, or will it eventually get reassigned at some point? Is there anything I can do to test for this?

Once again, thanks for your time in reading this.

Share this post


Link to post
Share on other sites
[quote]that the address previously used would be re-used so long as something was assigned to the pointer straight after it was deleted.[/quote]

Despite leaky abstraction, memory address in C++ is an opaque blob. It has no meaningful value conceptually, so one cannot argue about reusability.

Pointer arithmetic is defined for allocated memory. Or, if I allocate N bytes using new and getting pointer P, then I may apply pointer arithmetic on range P..P+N. What 'P' is or how it's represented is not sufficiently defined. While it can be viewed as an int, it is not really an int. DOS had segmented model which made such reasoning invalid, yet correct C++ code can work in such memory model.

Once I call delete on P, these operations aren't valid anymore.

Anything that uses literal address without respecting the above rule is undefined behavior. The rest is up to runtime implementation and OS.

A memory leak means many things, but in general, it means that during life-time of application:
- there were more 'new' than 'delete' calls (memory leak)
- there were more 'delete' than 'new' calls (dangling pointer) Edited by Antheus

Share this post


Link to post
Share on other sites
Thank you very much for your response. It has given me food for thought.

With my included example: I destroy the image -> call delete on the object that stored the image (after which the attributes displayed in the debugger become invalid/negative values (-17million)), and erase it's position in the vector afterwards...... That it is safe to say that the object is deleted and the memory address has been successfully freed?

Thanks.

Share this post


Link to post
Share on other sites
If you call delete in C++, even once, the object's directly owned memory [b]is[/b] freed. Period.

The trick of memory management is calling delete [i]exactly once[/i], and at the right time. This is a sufficiently difficult problem that it is advisable to rely on automatic pointers such as unique_ptr and shared_ptr instead of manually handling your news/deletes.

The other side of things is indirect resource ownership. If you delete an object that holds a pointer, that pointer is not freed automatically by default. You need to use the class destructor to free up any memory that the object owns beyond its own "self." Other resources that often leak include files, sockets, OS handles, and so on.

In C++ we use the "RAII" (resource acquisition is initialization) idiom to help defend against this. Smart pointers and smart containers are generally implemented to use RAII. I recommend looking into it if you're concerned about making sure your code handles resource cleanup nicely (and you should be!).

Share this post


Link to post
Share on other sites

This topic is 2044 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.

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