OOP object destruction

  • (2 Pages)
  • +
  • 1
  • 2

22 Replies - 3421 Views - Last Post: 10 September 2009 - 05:04 PM Rate Topic: -----

#1 Xioshin  Icon User is offline

  • D.I.C Regular

Reputation: 4
  • View blog
  • Posts: 264
  • Joined: 05-November 08

OOP object destruction

Posted 09 September 2009 - 09:33 AM

Hi, I'm trying to figure out how to get a destructor to run and them destroy an object. If we had a class named Person, I would do something like
 Person p1; 


when I use sdl, I want to create an object and load in an image surface attached to that object. I thought it would be great in terms of OOP to be able to run SDL_FreeSurface as part of the destructor, in order to better manage memory!

So my question is, how can I tell an object to die?

Is This A Good Question/Topic? 0
  • +

Replies To: OOP object destruction

#2 KYA  Icon User is offline

  • Wubba lubba dub dub!
  • member icon

Reputation: 3202
  • View blog
  • Posts: 19,232
  • Joined: 14-September 07

Re: OOP object destruction

Posted 09 September 2009 - 09:35 AM

When an object goes out of scope, the destructor is called. Generally you'd want to create an object on the heap, so when you delete the pointer to free the memory you know that the destructor is called.


You don't call the destructor explicitly.
Was This Post Helpful? 0
  • +
  • -

#3 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 7150
  • View blog
  • Posts: 14,893
  • Joined: 16-October 07

Re: OOP object destruction

Posted 09 September 2009 - 10:04 AM

Nothing better than writing a demo program to see how objects live. All experiments need rats...

#include <iostream>

using namespace std;

class Rat {
private:
	static int ratCount;
	string name;
	void showStatus(string s) { cout << s << ": "<< id << " " << name << endl; }

public:
	const int id;
	Rat(const std::string &r) : id(++ratCount), name® { showStatus("Create"); }
	Rat() : id(++ratCount), name("Rat") { showStatus("Create"); }
	~Rat() { showStatus("Die"); }
};

int Rat::ratCount = 0;


void Cage() {
	cout << "Enter cage." << endl;
	// pinky will only survive until we leave this function
	Rat r("Pinky");
	cout << "Leave cage." << endl;
}

int main() {
	// a rat pointer, this you can kill
	Rat *rp;
	
	// you can't kill Ben, the program will kill him for you
	Rat ben("Ben");
	
	rp = new Rat("Wilbur");
	Cage();
	delete rp; // kill Wilbur now
	Cage();
	
	return 0;
};



Results:
Create: 1 Ben
Create: 2 Wilbur
Enter cage.
Create: 3 Pinky
Leave cage.
Die: 3 Pinky
Die: 2 Wilbur
Enter cage.
Create: 4 Pinky
Leave cage.
Die: 4 Pinky
Die: 1 Ben


Was This Post Helpful? 0
  • +
  • -

#4 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 09 September 2009 - 01:07 PM

Baavgai, that's a great example, but I'm curious as to the initial question.

If all of the objects were being created during the main game loop, we would want to be able to destroy them when needed. We can't just go and leave the main game loop within main()....

For example, we create an object of an enemy. The destructor will have the necessary pieces to free the image surface of the enemy sprite. If the player's bullet (or whatever) hits the enemy, the enemy will die.

How would you "destroy" the object in this case? I haven't been able to figure this out, but it is EXTREMELY common in almost ALL games.

This post has been edited by BlackPhoenix: 09 September 2009 - 02:06 PM

Was This Post Helpful? 0
  • +
  • -

#5 mono15591  Icon User is offline

  • D.I.C Regular

Reputation: 12
  • View blog
  • Posts: 406
  • Joined: 05-November 08

Re: OOP object destruction

Posted 09 September 2009 - 01:52 PM

View PostBlackPhoenix, on 9 Sep, 2009 - 12:07 PM, said:

Baavgai, that's a great example, but I'm curious as to the initial question.

If all of the objects were being created during the main game loop, we would want to be able to destroy them when needed. We can't just go and leave the main game loop within main()....

For example, we create an object of an enemy. The destructor will have the necessary pieces to free the image surface of the enemy sprite. If the player's bullet (or whatever) hits the enemy, the enemy will die.

How would you "destroy" the object in this case? I haven't been able to figure this out, but it is EXTREMELY common in almost ALL games.


wouldn't a simple check of all objects be good enough with all of the objects having a bool for being dead or alive

if(object.dead()==true)
	 delete object;

This post has been edited by mono15591: 09 September 2009 - 01:53 PM

Was This Post Helpful? 0
  • +
  • -

#6 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1397
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: OOP object destruction

Posted 09 September 2009 - 01:53 PM

Quote

How would you "destroy" the object in this case? I haven't been able to figure this out, but it is EXTREMELY common in almost ALL games.
So, we can assume you read the two replies above you and completely understood them?

Because, then you can explain back to use what KYA meant with "Generally you'd want to create an object on the heap, so when you delete the pointer to free the memory you know that the destructor is called." and from Baavgai's code example: "delete rp;".
Was This Post Helpful? 0
  • +
  • -

#7 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 09 September 2009 - 02:07 PM

View PostOler1s, on 9 Sep, 2009 - 12:53 PM, said:

So, we can assume you read the two replies above you and completely understood them?

Because, then you can explain back to use what KYA meant with "Generally you'd want to create an object on the heap, so when you delete the pointer to free the memory you know that the destructor is called." and from Baavgai's code example: "delete rp;".


Well baavgai instructed to create a rat pointer, and then have the pointer point to a new rat named Wilbur.

What if we are creating more than 1 rat. Do I need a pointer for each one?

What about "respawning" enemies, randomly created enemies on timers, etc.

We cant just have a bunch of pointers can we? How do we dynamically name them? This is the stuff I was trying to get clarified :). And you are right, no I do not have a good grasp of this all yet. I am trying to learn though! Thanks for the help

This post has been edited by BlackPhoenix: 09 September 2009 - 02:08 PM

Was This Post Helpful? 0
  • +
  • -

#8 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1397
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: OOP object destruction

Posted 09 September 2009 - 02:25 PM

Quote

What if we are creating more than 1 rat. Do I need a pointer for each one?
Yes. You need some data structure to store multiple pointers, something like an array, or maybe something more depending on your needs (i.e. it doesn't involve pointers).

Quote

What about "respawning" enemies, randomly created enemies on timers, etc.
You can't create variables on the fly. That's not a meaningful concept. What you do want is a data structure that ultimately can be managed in such a way. And then set of algorithms that operate on that data structure. It sounds abstract, but consider how you would manage such a thing by hand.

You would probably keep a list of some sort, with additional information allowing you to manage this list, right? And then, operating on this list passes through some implicit interface. If you were the game master, doing everything by hand, some sort of event would require that you create a new enemy, or destroy an existing one. You would verify this request, and then do something on your pen and paper list. You have the same sort of requirements in code.

I think it really helps to go through a fundamental data structures and algorithms course or books or whatever. You need to stop thinking in terms of "how do I do this in C++" and start thinking in terms of logical abstractions. Once you figure out the kind of abstractions you need, you can then start dealing with the question of "how do I actually implement that logic in C++"

This post has been edited by Oler1s: 09 September 2009 - 02:26 PM

Was This Post Helpful? 0
  • +
  • -

#9 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 7150
  • View blog
  • Posts: 14,893
  • Joined: 16-October 07

Re: OOP object destruction

Posted 09 September 2009 - 05:10 PM

View PostBlackPhoenix, on 9 Sep, 2009 - 02:07 PM, said:

For example, we create an object of an enemy. The destructor will have the necessary pieces to free the image surface of the enemy sprite. If the player's bullet (or whatever) hits the enemy, the enemy will die.


There are two different critters here, it's easy to confuse them. From the OP, I take "object" to mean an instance of a class. In this case, a distinct object is created in memory when I call the constructor. It's destroyed, or deleted, or freed, when the variable that holds it goes out of scope or is explicitly released with a delete. It's all too easy to create memory leaks in C++, e.g. "new Rat(); return;"

You seem to be talking about the how a game object interacts with a game environment. In this scenario, it's not required that a class instance be destroyed when the game object is; only that the game handles it's state correctly. The game object can be marked dead, but still exist in memory, waiting to be resurrected for the next round.
Was This Post Helpful? 0
  • +
  • -

#10 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 09 September 2009 - 07:08 PM

Been playing around with this a bit:

#include <iostream>
#include <string>
using namespace std;

class Rat
{
	private:
		string name;
	public:
		Rat(string n); // constructor
		~Rat(); // destructor
		void sayHello();
		
};


Rat::Rat(string n)
{
	name = n;
	cout << n << " created.\n";
}

Rat::~Rat()
{
	cout << name << " destroyed.\n";

}

void Rat::sayHello()
{
	cout << name << " says Hello!\n";
}

int main()
{
	Rat *ptr_array[100]; // create a pointer array for 100 possible objects
	ptr_array[0] = new Rat("Baavgai");
	ptr_array[1] = new Rat("Black Phoenix");
	
	//THESE MUST BE EXPLICITLY DELETED. THE PROGRAM WILL NOT DELETE THESE 
	//AFTER WE HAVE LEFT THE SCOPE OF MAIN!!!
	system("pause");
	
	cout << "Address of ptr_array[1]: " << &ptr_array[1] << endl;
	ptr_array[1]->sayHello();
	delete ptr_array[1];
	cout << "Address of ptr_array[1]: " << &ptr_array[1] << endl;
	system("pause");
	
	delete ptr_array[0];
	return 0;
}




After I delete the 2nd object (ptr_array[1]), it still exists as an entry in my array. How can I remove it from the array of pointers?

Please do your best to make this more clear :) I am learning thanks to you all
Was This Post Helpful? 0
  • +
  • -

#11 KYA  Icon User is offline

  • Wubba lubba dub dub!
  • member icon

Reputation: 3202
  • View blog
  • Posts: 19,232
  • Joined: 14-September 07

Re: OOP object destruction

Posted 09 September 2009 - 07:14 PM

Use a vector:

vector<Rat*> myRats;

Rat* temp = new Rat("KYA"); //allocate
myRats.push_back(temp); //pass the pointer into this, you'll access the rat from here hence forth

//do rat stuff

//now, this is IMPORTANT!
//you must free the memory allocated
//we will not use the temp handle, we will iterate through the vector:


vector<Rat*>::iterator iter;
for(iter = myRats.begin(); iter != myRats.end(); ++iter) {
	 delete (*iter); //free each and every remaining pointer
}
myRats.clear(); //clean out any handles


Was This Post Helpful? 0
  • +
  • -

#12 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 09 September 2009 - 08:33 PM

! Thanks for your help

Had to read many tutorials because Vectors were completely knew to me.

To recap, what I needed was a way for me to create and destroy objects as I needed them, and a container that I could easily maintain each object, in order to get it to 1) DO THINGS 2) DIE

This is what I was able to cook up:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Player
{
	private:
		string name;
		int x, y;
	public:
		Player(string n); // constructor
		~Player(); // destructor
		void sayHello();
		
};


Player::Player(string n)
{
	name = n;
	cout << name << " created. -- constructor\n";
}

Player::~Player()
{
	cout << name << " destroyed. -- destructor\n";

}

void Player::sayHello()
{
	cout << name << " says Hello! -- member function\n";
}


int main()
{
	vector<Player*> myPlayers;
	Player* temp;
	cout << "Current size of vector: " << myPlayers.size() << endl;

	temp = new Player("Player1");
	myPlayers.push_back(temp);
	cout << "Current size of vector: " << myPlayers.size() << endl;

	temp = new Player("Player2");
	myPlayers.push_back(temp);
	cout << "Current size of vector: " << myPlayers.size() << endl;
	
	vector<Player*>::iterator myIterator;
	for(myIterator = myPlayers.begin(); myIterator != myPlayers.end(); ++myIterator)
	{
		//cout << myPlayers.at(myIterator)->sayHello << endl;   //trying to make this work
		delete *myIterator;
		
	}

	myPlayers.clear();
	cout << "Current size of vector: " << myPlayers.size() << endl;
	system("pause");
	return 0;
}



The output is:
Current size of vector: 0
Player1 created. -- constructor
Current size of vector: 1
Player2 created. -- constructor
Current size of vector: 2
Player1 destroyed. -- destructor
Player2 destroyed. -- destructor
Current size of vector: 0
Press any key to continue . . .



This is EXACTLY what I wanted to happen.

You'll notice one issue though, I am still unsure how to do two things.

1) Tell only one object to do something without having to run through an iterator loop

2) Have the iterator(the pointer to the current object) have the object run its functions when I need/want it to. I had to comment this line out because I was getting errors after playing with it to try and get it working. The "intellisense" or w/e they call it in Visual C++ 2008 Express was pushing me to the right path by letting me see available function calls, so I knew I was getting close!

If you could finish up by explaining these 2 points then I think I've learned a hell of a lot! I will then turn this into an easy-to-read document and save it so I can always use it as a vector reference!
Was This Post Helpful? 0
  • +
  • -

#13 KYA  Icon User is offline

  • Wubba lubba dub dub!
  • member icon

Reputation: 3202
  • View blog
  • Posts: 19,232
  • Joined: 14-September 07

Re: OOP object destruction

Posted 09 September 2009 - 08:45 PM

Well with this approach, we give up any pointer names for the ability to dynamically adjust our collection. What you could do is a search function that returns the index of the object you want.

If the object chosen has anything to do with user input, then you could somehow use it to choose the right index (you can use the subscript operator to do so).

As for function running, here's a quick example I threw together. The iterator can be though of as a pointer, so you dereference (to get to the actual pointer) which you then use the indirection operator to call functions:

#include<iostream>
#include <vector>
#include <string>
using namespace std;

class Rat{
private:
	string name;
public:
	Rat()					{name = "Default rat";};
	Rat(string name)		{this->name = name;};
	~Rat() {};
	string getName()		{return name;};
	void speak()			{ cout << this->getName() << " is making rat noise!" << endl;};
};

int main()
{
	vector<Rat*> someRats;
	Rat* temp = new Rat("KYA");
	someRats.push_back(temp);
	temp = new Rat();
	someRats.push_back(temp);

	vector<Rat*>::iterator iter;
	for(iter = someRats.begin(); iter != someRats.end(); ++iter) {
		(*iter)->speak();//calling a function
	}

	//clean up
	for(iter = someRats.begin(); iter != someRats.end(); ++iter) {
		delete (*iter);
	}
	return 0;
}


Was This Post Helpful? 0
  • +
  • -

#14 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 09 September 2009 - 09:10 PM

All clear now
Current size of vector: 0
Player1 created. -- constructor
Current size of vector: 1
Player2 created. -- constructor
Current size of vector: 2
Jeremy says Hello! -- member function
Jeremy destroyed. -- destructor
Luke says Hello! -- member function
Luke destroyed. -- destructor
Current size of vector: 0
Press any key to continue . . .



but I realized if I want to do something with only ONE object, it is perfectly OK to do this:

myPlayers.at(1)->sayHello();  //tell 2nd object to run a function
delete myPlayers.at(1);  // destroy the second function



----------------------------------------
After some time to practice, I was able to make this final program, exercising my new-found knowledge of the things I can and cannot do using vectors! Thanks KYA!

CODE
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Player
{
	private:
		string name;
		int x, y, age;
	public:
		Player(string n); // constructor
		~Player(); // destructor
		void setAge(int in_age);
		int getAge();
		void sayHello();
		
};


Player::Player(string n)
{
	name = n;
	cout << name << " created. -- constructor\n";
}

Player::~Player() { cout << name << " destroyed. -- destructor\n"; }

void Player::sayHello() { cout << name << " says Hello! -- member function\n"; }

void Player::setAge(int in_age) 
{ 
	age = in_age; 
	cout << name << " age set to " << age << endl;
}

int Player::getAge() { return age; }

int main()
{
	vector<Player*> myPlayers;
	Player* temp;
	cout << "Current size of vector: " << myPlayers.size() << endl;

	temp = new Player("Jeremy");
	myPlayers.push_back(temp);
	cout << "Current size of vector: " << myPlayers.size() << endl;

	temp = new Player("Luke");
	myPlayers.push_back(temp);
	cout << "Current size of vector: " << myPlayers.size() << endl;
	
	// give Players ages by using our new vector!
	myPlayers.at(0)->setAge(22);
	myPlayers.at(1)->setAge(21);

	vector<Player*>::iterator myIterator;
	for(myIterator = myPlayers.begin(); myIterator != myPlayers.end(); ++myIterator)
	{
		(*myIterator)->sayHello(); // run sayHello() function

		//destroy object if object has an age less than 22
		int objectAge = (*myIterator)->getAge();
		if (objectAge < 22)
		{
			delete (*myIterator);
		}
	} 
	//myPlayers.at(1)->sayHello(); // tell 2nd object to do something
	//delete myPlayers.at(1); // destroy 2nd object

	myPlayers.clear();
	cout << "Current size of vector: " << myPlayers.size() << endl;
	system("pause");
	return 0;
}



OUTPUT
Current size of vector: 0
Jeremy created. -- constructor
Current size of vector: 1
Luke created. -- constructor
Current size of vector: 2
Jeremy age set to 22
Luke age set to 21
Jeremy says Hello! -- member function
Luke says Hello! -- member function
Luke destroyed. -- destructor
Current size of vector: 0
Press any key to continue . . .


Was This Post Helpful? 0
  • +
  • -

#15 BlackPhoenix  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 152
  • Joined: 11-July 09

Re: OOP object destruction

Posted 10 September 2009 - 11:47 AM

I'm trying to take the code I made from my previous post and incorporate it into my already existing program:

Here is the most important piece of code, main.cpp:

#include <SDL.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include "Player.h"
using namespace std;

int main(int argc, char* args[])
{
	ofstream log;
	log.open ("log.txt");

	const int SCREEN_WIDTH = 640;
	const int SCREEN_HEIGHT = 480;
	const int SCREEN_BPP = 32;

	SDL_Surface* screen = NULL;
	log << "screen address: " << screen << endl;

	bool quit = false;
	SDL_Event event;

	/*	INITIALIZATION	*/
	SDL_Init(SDL_INIT_EVERYTHING); 

	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
	log << "screen surface address: " << screen << endl;
	SDL_WM_SetCaption("Sentinel", NULL);
	
	//create vector to store objects
	vector<Player*> Players;
	Player* temp;

	//create objects in vector
	temp = new Player(100, 100);
	//Players.push_back(temp); // <-- the line giving me problems

	//create objects from class only
	Player background(0, 0);
	background.Load("background.bmp");
	Player hero(200, 200);
	hero.Load("hero.bmp");

	
	/*		   MAIN LOOP		*/
	while (quit == false)
	{
		/*		HANDLE USER INPUT		*/
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{	
				case SDL_QUIT:
					quit = true;
					break;
			}
		}
		


		/*		UPDATE		 */ 
		SDL_FillRect(screen, NULL, 0x00000000); // clear screen
		background.Draw(screen);
		hero.Draw(screen);



		/*		  DRAW		 */
		if (SDL_Flip(screen) == -1)
		{
			log << "Screen could not be flipped\n";
			return 1;
		}
	}

	/*	   CLEAN	   */
	SDL_Quit();
	log.close();
	return 0;
}




Everything works like a charm, including the creation of objects, as well as drawing the objects onto the screen.

What I am trying to do now is have these objects be put into a vector so I can maintain all of them (see the previous post).

I am able to create the vector Players, as well as temp, but when I uncomment the line
Players.push_back(temp);
I get these errors:

1>Main.obj : error LNK2001: unresolved external symbol __imp___CrtDbgReportW
1>C:\Users\Jeremy\Development\C++\Sentinel\Debug\Sentinel.exe : fatal error LNK1120: 1 unresolved externals
1>Build log was saved at "file://c:\Users\Jeremy\Development\C++\Sentinel\Sentinel\Debug\BuildLog.htm"
1>Sentinel - 2 error(s), 0 warning(s)



What could be the issue? If it helps, pressing F7 to build again, gives me a different, more detailed error:

1>Main.obj : error LNK2019: unresolved external symbol __imp___CrtDbgReportW referenced in function "public: __thiscall std::_Vector_const_iterator<class Player *,class std::allocator<class Player *> >::_Vector_const_iterator<class Player *,class std::allocator<class Player *> >(class Player * *,class std::_Container_base_secure const *)" (??0?$[email protected]@@V?$[email protected]@@@[email protected]@@[email protected]@[email protected]@@[email protected]@@Z)
1>C:\Users\Jeremy\Development\C++\Sentinel\Debug\Sentinel.exe : fatal error LNK1120: 1 unresolved externals


Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2