Skip to main content
GameDev.net gamedev.net
🔒 Locked

ObjectManager Class Design Question

Started by MindVampire Jan 22, 2005 at 4:48 AM 16 replies 1.6k views
Original Post
MindVampire
MindVampire
Hi there! I want to create an ObjectManager class, which handles freeing memory if objects are not longer used. But I just have a little problem with c++ documentation :) (I'm using g++ and SDL for a cross-platform project, so I cannot use VC++ thingies...) I'm just posting my "pseudocode" attempts in here for your review, perhaps you can help me some... objman.cpp (I'v just put it into one file for easier coding, seperating it later into objman.h and objman.cpp)

class CObjectManager {
  
  Object[] ObjectList[10]; // array to store objects in
  int numObjects; // number of stored objects

  public:
    explicit CObjectManager() {
      add(this); // perhaps storing myself?
    };
    virtual ~CObjectManager() {
      delete[] ObjectList; // sth like that to prevent mem-leakage
    }

    void add(Object* obj) {
      ObjectList[numObjects] = obj; // add object pointer to array
      numObjects++;

      // here should be some check if array limits were exceeded
      // and copy it into new memory area and free the old one (sth. like that)
    }

    void wipe() {
      for (int i=numObjects; i>0; i--) {
        delete *ObjectList; // delete object to which list entry points
      }
      numObjects = 0;
    }
};
main.cpp

--- snip ---

  CObjectManager *ObjectManager = new CObjectManager();

  // Creating a new arbitrary Object which the objman should be able to handle
  CMyObject *MyObject = new CMyObject();
  MyObject->Blah();
  MyObject->SetFoo(bar);
...
  
  // one simple call should delete all objects
  ObjectManager->wipe();
  delete ObjectManager; // don't know how to let him delete himself

--- snip ---
CMyObject Constructor

CMyObject::CMyObject() {
  ObjectManager->add(this);
}
snk_kid
snk_kid
You didn't actually say what your problem is so i'll just give some comments.

Quote:
Original post by MindVampire
Object[] ObjectList[10]; // array to store objects in



i'm surprised if that compiles, or is that a typo?

Quote:
Original post by MindVampire
explicit CObjectManager() {      add(this); // perhaps storing myself?};



I don't get the point of making a default constructor explicit? and you can't add itself unless CObjectManager is sub-type of Object.

Quote:
Original post by MindVampire
virtual ~CObjectManager() {  delete[] ObjectList; // sth like that to prevent mem-leakage}



well that line will implode, ObjectList is a statically allocated array.

Quote:
Original post by MindVampire
void wipe() {   for (int i=numObjects; i>0; i--) {      delete *ObjectList; // delete object to which list entry points   }   numObjects = 0;}



operator delete works on pointers, and even if that was okay the idea of CObjectManager deleting items it never created itself has potential problems what i mean is if you look at your add method:


Quote:
Original post by MindVampire
void add(Object* obj) {  ObjectList[numObjects] = obj; // add object pointer to array  numObjects++;



So who is the owner, CObjectManager? the client that passes obj to add?

if CObjectManager then how can you guarantee that a client wont call operator delete out side of CObjectManager and then CObjectManager calling operator delete on memory that doesn't exist any more.

Also you have subtle problem if you add the address of CObjectManager to that array then you call delete on it in that wipe method leaving your code in some undefined state even if it worked you then call delete outside of CObjectManager where the memory doesn't exist anymore.

Quote:
Original post by MindVampire
CMyObject Constructor
CMyObject::CMyObject() {  ObjectManager->add(this);}



The way you currently have it, if an instance of CMyObject is statically allocated, then your program is going to implode, other than that design wise its a little to intrusive & tightly coupled.

I think you need to get your self a good book on C++.
MindVampire
MindVampire
ok so you didn't read my post very attentive.

i DID say this is just PSEUDOCODE
all i wanted to show is what i have in mind.

i HAVE a good book on c++: ulrich breymann - c++ einführung und professionelle programmierung (hanser)

to specify my question:

i need to know how to store arbitrary objects into a dynamic list.

another thing: i DON'T like rants plus i DON'T like RTFM-answers.
i AM NO NOOB, i just DON'T KNOW what exactly to search for.
thanks in advance.
snk_kid
snk_kid
Quote:
Original post by MindVampire
i need to know how to store arbitrary objects into a dynamic list.


You have a thew choices:

A. You have base class and store (smart) pointers of the base type in a list e.g.

#include <list>//...std::list<Base*> list_of_objs;


B. Download the boost library and have a list of boost::any:

#include <boost\any.hpp>#include <list>//..std::list< boost::any > list_of_any;


C. Have a list of void pointers (ugly don't think even about it).

Quote:
Original post by MindVampire
another thing: i DON'T like rants plus i DON'T like RTFM-answers.
i AM NO NOOB, i just DON'T KNOW what exactly to search for.


Your taking it to personally, i'm just telling you the potential problems your code can have if you have it that way i'm giving you advice, no-one can read your mind as to what your problem is.
MindVampire
MindVampire
... *swallows*
sorry for my answer, got just one too much like yours.
i was googlin the hell out of inet and just came to no clue.

... hm, lists that of course helps a lot.

what is meant by
Base*
is this a pointer to my object or to some abstract superparent object?

i've looked at www.cppreference.com for lists but cannot find there what you described.

the code
#include <list>void main(void) { std::list<Base*> mylist;}


led to the following error:
ISO C++ forbids declaration of `list' with no type
snk_kid
snk_kid
Quote:
Original post by MindVampire
what is meant by
Base*
is this a pointer to my object or to some abstract superparent object?


Base was just a hypothetical type, if Object is your root class then you would replace Base* with Object* (pointer to Object).

Quote:
Original post by MindVampire
i've looked at www.cppreference.com for lists but cannot find there what you described.


Its in there, look at this section, you might want to bookmark this link aswell.

To help with problems like ownership that i described earlier i recommend looking into & using smart pointers, the boost library has an excellent package of smart pointer types (which are likely to be part of the C++ standard in the future).

Boost is closely linked with the C++ standard, think of boost as standard C++'s older sister, she helps contain the little beast of its pure raw-ness.

EDIT: This seems like a good introduction on smart pointers
MindVampire
MindVampire
thanks, that helps a alot.
i'm trying it,... reporting on success :)
MindVampire
MindVampire
hm... damn class structure.

i'm just trying to create something like this (PSEUDOCODE)
class OBJECT {  public:    OBJECT() { OBJECT_MANAGER.ADD(this); }};class OBJECT_MANAGER {  LIST OBJECT_LIST;  public:    OBJECT_MANAGER() { INIT(); }    void ADD(OBJECT* OBJ) { OBJECT_LIST.ADD(OBJ); }};



but this compiles with following errors:
#include <list>class CObject {  public:    CObject() { CObjectManager.add(this); } // `CObjectManager' undeclared (first use this function) };class CObjectManager {  list<CObject*> ObjectList; // ISO C++ forbids declaration of `list' with no type   public:    CObjectManager() {};    void add(CObject* obj) { ObjectList.push_back(obj); }};int main(void) {  CObjectManager *ObjectManager = new CObjectManager();  // some time later...  delete ObjectManager;  return 0;}
Evil Steve
Evil Steve
Quote:
Original post by MindVampire
#include <list>class CObject {  public:    CObject() { CObjectManager.add(this); } // `CObjectManager' undeclared (first use this function) };


How does CObject know what CObjectManager to add itself to? You could pass the CObjectManager as a parameter to the constructor, or (better) you could make CObjectManager a singleton. E.g.
class CObjectManager{private:   CObjectManager() {} // Private constructorpublic:   static CObjectManager& Get()   {      static CObjectManager theMgr;      return theMgr;   }private:   list<CObject*> ObjectList;   // Normal methods //public:    void add(CObject* obj) { ObjectList.push_back(obj); }};

and then, in your CObject constructor:
class CObject{public:   CObject() { CObjectManager::Get().add(this); }};

I suspect that the "ISO C++ forbids declaration of `list' with no type" error is because CObject is in a different file from CObjectManager? The compiler only compiles one module (.cpp) file at a time. If you want it to know about CObject, you need to either include the CObject header in the CObjectManager header, or use class CObject; to let the compiler know that there's something called CObject. But you'll only be able to use pointers or references to the object, you won't be able to call any methods from it, oor create any instances of it until the compiler sees the full declaration.
MindVampire
MindVampire
so thats interesting.

i just tried this and it looks promising, but i still get the error:
ISO C++ forbids declaration of `list' with no type 


here are my sources:

includes.h
#include <cstdlib>#include <list>#include "object.h"#include "objman.h"using namespace std;


main.cpp
#include "includes.h"int main(int argc, char *argv[]){  CObjectManager ObjectManager = CObjectManager::Get();  return 0;}


object.h
#ifndef OBJECT#define OBJECTclass CObject {  public:    CObject();};#endif


object.cpp
#include "includes.h"CObject::CObject() {  CObjectManager::Get().Add(this);}


objman.h
#ifndef OBJECT#include "object.h"#endif#ifndef OBJMAN#define OBJMANclass CObjectManager {    private:    CObjectManager();    public:    static CObjectManager& Get();  private:    list<CObject*> ObjectList;    public:    void Add(CObject* Object);};#endif


objman.cpp
#include "includes.h"static CObjectManager& CObjectManager::Get() {  static CObjectManager ObjectManager;  return ObjectManager;}void CObjectManager::Add(CObject* Object) {  ObjectList.push_back(Object);}
Evil Steve
Evil Steve
Hmm... I've no idea. What happens if you cange the type to list? However, you don't need this line: CObjectManager ObjectManager = CObjectManager::Get();. That'll make a copy of the object manager.
JimPrice
JimPrice
Objman.h doesn't #include - therefore it doesn't know what list is.

As a general aside - your includes could do with a looking at. I'll pre-empt Zahlman (as he always seems to be posting this) and recommend this link.

Jim.
MindVampire
MindVampire
ok, how can i access the objectmanager then from main to do sth like that:

...ObjectManager.DeleteAll(); // same as for each object: delete Object;
Evil Steve
Evil Steve
Quote:
Original post by MindVampire
ok, how can i access the objectmanager then from main to do sth like that:

...ObjectManager.DeleteAll(); // same as for each object: delete Object;

CObjectManager::Get().DeleteAll();

CObjectManager::Get() returns the one instance of CObjectManager.

MindVampire
MindVampire
same procedure with
list<int*>...


Compiler: Default compilerBuilding Makefile: ".\objectmanager\Makefile.win"Führt  make clean ausrm -f main.o objman.o object.o  objectmanager.exeg++.exe -c main.cpp -o main.o -I"C:/Dev-Cpp/include/c++"-I"C:/Dev-Cpp/include/c++/mingw32"  -I"C:/Dev-Cpp/include/c++/backward"-I"C:/Dev-Cpp/include"In file included from includes.h:4,                 from main.cpp:1:objman.h:20: error: ISO C++ forbids declaration of `list' with no typeobjman.h:20: error: expected `;' before '<' tokenmake.exe: *** [main.o] Error 1
JimPrice
JimPrice
OK - here's my go at your code.

main.cpp
// Don't include un-necessary things - your generic file includes several items main doesn't need to be aware of//#include "includes.h"#include "objman.h"int main(int argc, char *argv[]){  CObjectManager ObjectManager = CObjectManager::Get();  return 0;}


object.h
// Fine.#ifndef OBJECT#define OBJECTclass CObject {  public:    CObject();};#endif


object.cpp
// Nope - not needed//#include "includes.h"#include "objects.h"#include "objman.h"CObject::CObject() {  CObjectManager::Get().Add(this);}


objman.h
// None of this is needed - let object.h decide whether it's been included itself/*#ifndef OBJECT#include "object.h"#endif*/#ifndef OBJMAN#define OBJMAN#include <list>// If only a pointer to the object is specified, don't need a full #include - this will doclass CObject;class CObjectManager {    private:    CObjectManager();    public:    static CObjectManager& Get();  private:// Don't pollute your namespace with 'using namespace std' - it's bad practice    std::list<CObject*> ObjectList;    public:    void Add(CObject* Object);};#endif


objman.cpp
//#include "includes.h"#include "objman.h"static CObjectManager& CObjectManager::Get() {  static CObjectManager ObjectManager;  return ObjectManager;}void CObjectManager::Add(CObject* Object) {  ObjectList.push_back(Object);}


I recommended reading the link I provided to understand why I made the changes I did.

Quote:

ok, how can i access the objectmanager then from main to do sth like that:


The code above will now work fine if you add the declaration and definition of the new function in objman to your existing code.

HTH,
Jim.
MindVampire
MindVampire
thanks Jim, that makes it very clear now. :)

with a little debugging i got it running.
removed the static in the get() method
and added the CObjectManager constructor
in objman.cpp

#include "objman.h"CObjectManager::CObjectManager() { }CObjectManager& CObjectManager::Get() {  static CObjectManager ObjectManager;  return ObjectManager;}void CObjectManager::Add(CObject* Object) {  ObjectList.push_back(Object);}
MindVampire
MindVampire
just one little big question:

class CActor : public CObject {  CCoord Position;  double Angle;  double Speed;  public:    CActor() : CObject() {      InitActor(this); // some function call    }    bool MoveTo(int posX, int posY);    bool MoveBy(int deltaX, int deltaY);    bool MoveBy(double deltaA, int deltaD); // angle, distance    ...}


- will i be able to delete the
CActor *Actor = new CActor();

from whithin ObjectManager if adding by
CObjectManager::Get().Add((CObject*) Actor);


i thought of sth like that:
void CObjectManager::DeleteAll() {  // CObject *Object;  for(int i = ObjectList.size(); i > 0; i--) {    // Object = ObjectList.back();    // delete Object;    ObjectList.pop_back();  }}


but:
sizeof(CObject);
definitely returns another value than
sizeof(CActor);


or will just
ObjectList.clear();
free the whole memory??

[Edited by - MindVampire on January 23, 2005 2:11:46 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.