allocation/deallocation issues [general C++/vectors]

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

So... I've never really used vectors before but I'm having some issues with them, when I create a vector of n elements and then allocate it (algorithm below) it always generates n-1 slots filled (0 through n-2 specifically (if n is 8 it generates 0 through 6)).

Here's how I populate my build list.

Code: Select all

 
    for(int i = 0; i != indx-1; i++)
    {
        //@todo see to it to fix this weird allocation bug(?)...
        //It seems like it's really just due to a vector requiring
        //a minimum size which would explain 8 ints vs 32 bools.
        bList.push_back(true);
        loadID.push_back(0);
        nodes.push_back(NULL);
    }
    printf("bList contains %d elements with a capacity of %d\nloaded ID list contains %d elements with a capacity of %d\n", bList.size(), bList.capacity(), loadID.size(), loadID.capacity()); 
//This outputs a capacity of n elements with n elements allocated except for booleans if the total element count I try to allocate is smaller than 32 (I assume it's because vectors always allocate a minimum amount of data of 32 bytes).
 
//SNIP
    for( int index = 0; index != indx-1; index++)
    {
        
        if(loadID.at(index) == 0)
        {
            printf("adding entry to list\n");
            bList.at(index)=true;
        } //This only prints n-1 lines of "adding entry to list"
The issue with that is reasonably obvious (the actual result holds true as well, it generates exactly n-1 chunks which is annoying but noncritical), changing the for loop to anything else causes it to crash with an out of bounds access exception from the vector::at() call.
doing index != indx; causes it, starting with index -1 causes it, index <= indx-1; //or index, happens for any variation of the operators that can be used.
Further changing index++ to ++index changes nothing as well, it still generates exactly n-1 chunks.

More importantly though I have a similar critical bug in my deallocation code, if I use the above algorithm it leaks one chunk per 20 ticks (currently implemented as a tick increase per iteration of (device->run)) but if I don't use it it gets an out of bounds error and segfaults.
These bugs are reproducible on linux (GCC 4.8.x) and Windows 7 (ultimate x64) using MinGW 4.8.x with MSYS (no further environments have been tested).
I know the issue is with my code but I have been chasing this ghost for a week and I admit defeat, I can't win.

Code: Select all

     int index = nodes.size();
    if(nodes.size() != 0)
    for(int i = 0; i != index-1; i++)
    {
        delete &loadID.end(); //contains pointers to mesh data/scene node (couldn't think of an elegant way to store all chunk data in one package) 
        delete &nodes.end(); //contains pointers to chunk data
        nodes.pop_back();  //deletes the NULL pointer so it can be repopulated with a new pointer from the build list
        loadID.pop_back(); // --
    }
//This code crashes on deleting the last chunk, i != index; it crashes after deleting the last chunk, without the loop it crashes after deleting the last chunk (For obvious reasons, it just runs over and over and over
 
And that's my deallocation code.
The error is probably obvious but I can't for the life of me find it.
"this is not the bottleneck you are looking for"
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: allocation/deallocation issues [general C++/vectors]

Post by thanhle »

Why don't you delete from back to front? Start at the end and delete until 0 index.

Or use iterator to delete them?

Another thing. Make sure you delete any pointer which pointed to scenenodes inside the rendering loop before the begin scene or after the endscene.

Regards
thanh
Last edited by thanhle on Tue Apr 07, 2015 4:13 am, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: allocation/deallocation issues [general C++/vectors]

Post by CuteAlien »

OK, first the obvious comment - when you ask questions then at least always add the declarations of your involved variables. They usually contain half the answer :-) I suppose in this case it's something like the following?
std::vector<bool> bList;
std::vector<irr::ISceneNode*> loadID;
std::vector<ChunkData*> nodes;

Beside that I think you are confused about loop indices. I suppose when you speak of n you then mean 'indx' in your code? If your indx is 8 but your loop goes until your index is not the number 8-1 (aka 7...) then the numbers the loops goes through are 0-6. Which are also the numbers of your vector indices then (and yes, that's 7 elements). Just print out 'i' in each loop or use a debugger if you are not sure about that stuff.

Same mis-understanding in your de-allocation. You use index-1 but there is no reason to use -1. But there are 2 worse errors here. Your delete calls try to delete the memory of an iterator. What you want to delete is the content of the iterator instead which would be delete (*loadID.end()); and same with nodes.

There's also 2 optimizations you can do there. First is like thanhle proposed - start deleting from the end. Just be very sure to get your indices right so you still delete the first one (generally people use iterators only, not indices there). This will be a _lot_ faster in large arrays as it otherwise has to copy around all other elements behind the one you delete on each call.
The other optimization is - don't do the pop_back() in the loop. If you already know you delete all elements then you can just call .clear() after the loop to remove them all at once.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

Yes, my vectors are allocated exactly like that (because their size cannot be known until the render distance is known), the reason I use a -1 for the iterator is pretty simple, if I don't this happens:

Code: Select all

terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check
and I can't figure out why, it should work. (so I have an out of range or an off by one error, quite frustrating).
Same mis-understanding in your de-allocation. You use index-1 but there is no reason to use -1. But there are 2 worse errors here. Your delete calls try to delete the memory of an iterator. What you want to delete is the content of the iterator instead which would be delete (*loadID.end()); and same with nodes.

There's also 2 optimizations you can do there. First is like thanhle proposed - start deleting from the end. Just be very sure to get your indices right so you still delete the first one (generally people use iterators only, not indices there). This will be a _lot_ faster in large arrays as it otherwise has to copy around all other elements behind the one you delete on each call.
The other optimization is - don't do the pop_back() in the loop. If you already know you delete all elements then you can just call .clear() after the loop to remove them all at once.
I've never understood pointer deletion, so I don't have to delete the pointer contents first? Aight.

After reworking the code to include your suggestions there's now a slight improvement, it still crashes but it doesn't show an out of bounds exception so I don't even know why it crashes now (it doesn't print any of my tracer text so I know it crashes sometime after building the last chunk before reaching the unloadlist as there's a tracer entry before they are run).

Code: Select all

void chunkMgr::unloadList()
{
    int index = loadID.size();
    if(nodes.size() != 0)
    {
        for(int i = 0; i != index; i++)
        {
            printf("DELETING THINGS #%d\n",i);
            delete (*loadID.end());
            delete (*nodes.end());
        }
        printf("Do we clear the lists?\n");
        nodes.clear();
        loadID.clear();
    }
}//If we are to trust the tracer code it never runs this segment
 
//SNIP
 
void chunkMgr::buildList()
{
#warning "For some arcane reason it skips the last entry, this is non-critical for now"
    //@todo fixme, see notes from 4/4/2015
    printf("populating build list\n");
    
    if(bList.size() <= bList.capacity())
    {
        for(int i = bList.size(); i != bList.capacity(); i++ )
        {
            bList.push_back(true);
        }
    }
    else if(loadID.size() <= loadID.capacity())
    {
        for(int i = loadID.size(); i != loadID.capacity(); i++ )
        {
            loadID.push_back(0);
        }
    }
    
    for( int index = 0; index != indx; index++)
    {
        printf("indx %d\n",index);
        if(loadID.at(index) == 0)
        {
            printf("adding entry to list\n");
            bList.at(index)=true;
        }
        else
        {
            printf("do we ever see this?\n");
            bList.at(index)=false;
        }
    }
    build(); //It actually runs build because the timer code in the mesh generator runs and the mesh shows up
}
void chunkMgr::build()
{
    for(int index = 0; index != indx; index++)
    {
        if(bList.at(index) == true)
        {
          loadID.at(index) = new chunk(index);
          bList.at(index) = false;
        }
    }
}
 
 
 
I also knows it gets to the main loop, however my tracer code for printing off how many ticks it gets to does not run (just a printf which prints ticks: %d\n)
bList contains 8 elements with a capacity of 32
loaded ID list contains 8 elements with a capacity of 8
Time: 398 ms
Time: 440 ms
Time: 491 ms
Time: 538 ms
Time: 585 ms
Time: 628 ms
Time: 675 ms
Time: 714 ms
 
>Expected entries here, there were none
 
 
As for using a debugger, that'd be a nice idea except gdb doesn't play nice under MSYS on windows and I'm not going to debug my windows build under wine in linux.
 
Well ,the allocation bug is gone now... but instead I have another crash bug to deal with, perhaps I can coerce gdb into cooperation.
 
Oh yesh, my device loop:

Code: Select all

while(device->run())
    {
        ticks++;
        driver->beginScene(true, true, SColor(255,140,255,140));
        
        smgr->drawAll();
        guienv->drawAll();
        
        printf("tick %d\n");
        if(ticks == 20)
        {
            cMgr->poll();
            ticks=0;
        }
        
        driver->endScene();
    }
It clearly gets to smgr->drawall since things actually draw, it doesn't get to the printf() though... Or maybe I can't print from the main loop, I can still move the camera around for some 10 seconds before it crashes (however either terminal output gets suppressed at some point or can't be done after initiating the main loop (this I find fishy because with the allocation bug it'd actually get to polling the chunk manager and starting to create a new build list based on the output).
"this is not the bottleneck you are looking for"
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: allocation/deallocation issues [general C++/vectors]

Post by mongoose7 »

If you are using MSYS then you should know that output is buffered. You should put fflush(stdout) after any important printf's.
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: allocation/deallocation issues [general C++/vectors]

Post by thanhle »

If you read my comment.
It might solve both of the issues including your new crash issue.

Regards,
thanh
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

mongoose, I only use MSYS on my windows build environment (however I am completely unfamiliar with it aside from it spawning a bash shell under windows).
I'll see what happens if I flush the output buffer before important printfs.

thanhle, I'll re-read your comment, I must've missed something then.


EDIT: Flushing stdout does nothing, my tracer code still doesn't print to terminal.


As for your comment thanhle, I can only assume it must be the part about iterators as all my deletion and allocation happens inside the main loop (well rather, I poll the various list builders who then call the various build functions as required, the initial scene is built before the main loop however as that happens when the chunk manager is first instantiated (any other call to its members is done through the main chunk manager pointer)), the deletion part itself has already been sorted out as well so that indeed only leaves iterators. (which, draws a blank. a loop index should work but I'll look up iterators in this context to see what I can do).

Anyway, thanks for your answers :P I'm surprised you have such patience (given that I'm a rather incompetent programmer, I'm primarily an artist...)


EDIT2: Interestingly however all the discarded printfs DO show up if I run it in gdb or if I force the game to die before it crashes (they all appear in batch when the game exits normally or when gdb pauses it)
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

I officially don't understand iterators.

Code: Select all

VoxelNode.cpp:354:33: error: no matching function for call to 'std::vector<chunk*>::erase(std::vector<int>::iterator&)'
And why not? It works with an integer so why not with an iterator of type integer?

Anyway, my new deletion loop looks as follows, I'll keep messing with it but it's giving me a headache.

Code: Select all

void chunkMgr::unloadList()
{
    std::vector<chunk*>::iterator it;
    it = loadID.begin();
    while(it != loadID.end())
        {
            printf("DELETING THINGS #%d\n",it);
            delete (*loadID.end());
            delete (*nodes.end());
            it++;
        }
        printf("Do we clear the lists?\n");
        nodes.clear();
        loadID.clear();
}
Maybe I don't even need to do the whole erase thing, I could probably simplify it down to just calling deletes on them, incrementing the iterator and going until the loop terminates and then clearing the vectors which should have the same result (I assume).


EDIT: My chunk unloadlist now compiles, still crashes at the same place and I still don't understand iterators so I can't tell if I'm using them right (I'm allocating the iterator in the function, it's stack allocated (rather it behaves as if it was) and should scope out with the function hence I don't see this as a bad idea, local variables when possible).
At least this time I can count the ticks as they're going (ticks pass at a much slower rate than realtime so I can follow them for debugging purposes, I'll be using deltatime to determine tick count later but for now it is one tick per full loop iteration).
"this is not the bottleneck you are looking for"
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: allocation/deallocation issues [general C++/vectors]

Post by thanhle »

No hard feeling bro. I'm a newbie too : ).

Regards
thanh
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

thanhle wrote:No hard feeling bro. I'm a newbie too : ).

Regards
thanh
Well, I've been a newbie for numerous years now (mainly due to my inability of motivation, I get bursts of it then don't work at anything for weeks, thank [supernatural entity] that I at least have a good enough memory to retain most of the knowledge about my code so I can dive back in again).

Either way hacking at this at 3:57 am isn't going to help me, I should just get some sleep, maybe that'll help me see the issue.
"this is not the bottleneck you are looking for"
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: allocation/deallocation issues [general C++/vectors]

Post by CuteAlien »

OK, first step - get your debugger working, you can't program without one. And gdb works with MinGW perfectly fine. Guessing where it crashed is no replacement for seeing the line it crashed in. You can use the code::blocks IDE for your project - it handles all the hard parts of getting gdb working. And make sure your project is compiled with debug information.
I've never understood pointer deletion, so I don't have to delete the pointer contents first? Aight.
Yes, you do have to delete pointers first (or the content of them to be exact), at least if you did allocate the objects. That's what "delete (*loadID.end());" is doing now.

But... well, you can't use "delete (*loadID.end());" anymore, sorry about that. That worked in your old loop to replace the code you had there. But in your new loop you no longer remove the last vector element. So deleting the content of end() will delete the same element over and over as the end never changes. Which usually will crash on the second run through the loop.
But you can now use the easier "delete loadID;" when using the loop with the i counter (the one in your first answer). Same for nodes.

Using your last solution with iterator won't work like that - it's again deleting the same element at the end over and over in each loop-run. You could try to write loops which delete with iterators, but you need 2 loops then as you have only one iterator for one vector. It would look like "delete (*it);"

About your general confusing about iterators. They are a wrapper class which contains the real element of your vectors (or lists or maps or any other container class). The reasons for the wrapper is that it allows iterating over the elements directly. Meaning it has operators like ++ and -- which allow you to jump directly to the next or previous element. And the cool thing is that even works with some containers like std::map where it's not obvious which element would be next otherwise. And even cooler is that they allow to write algorithms which only know "there is some element" and "I can go to the next element with ++".

For example to write a search algorithm which doesn't need to know it's container type: It needs the iterator to start with and an iterator when it should stop and an element to search for. Then it can compare the element it searchs for to the content of the first iterator and if it's not the one it does a iterator++, checks if it has not reached the end and compares to the content the next one. The algorithm needs to know nothing else. It even works if you only search through parts of a vector (or list). And you can have really complicated structures - but as long as you write an iterator for them that allows to go through all elements with ++ you can use that search algorithm with it. STL <algorithm> uses this a lot - check out the functions in there some time, they are often useful.

But because an iterator is a wrapper you have to do *iterator to access the content (aka the real element) of it. And it helps to use brackets (*it) because when you have a pointer you often want to do stuff like (*it)->callSomeFunction() which won't work otherwise as doing *it->callSomeFuncton would try to call the function for the iterator instead of your real type (because -> has a higher precedence in c++ than *).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: allocation/deallocation issues [general C++/vectors]

Post by Cube_ »

I see.
Well, GDB itself works, it just doesn't play nice in the sense that it blatantly terminates with the application (clever breakpointing allows me to get around this, outputting to a log would also work) and I'm not to keen on using code::blocks, all the recent versions (10.04 being the last good one I tried) crash if I load anything but the default UI (under linux) and I've had issues with it becoming slow or just not behaving with large (~4k+ lines) projects (and I like using the same IDE on all platforms as maintaining multiple projects is less than nice), either way netbeans has some rather nice features so I'd rather not change it out for something else.

Right Right, I can't use the last vector if it's deleted (well, technically I *can* I just call delete on a dead pointer which is undefined, probably the source of the crash)
But you can now use the easier "delete loadID;" when using the loop with the i counter (the one in your first answer). Same for nodes.

I figured that wouldn't work, delete loadID.at(it); caused errors with an int vector (I can't actually tell if my implementation from 2 am was valid though because it's long since reverted... besides, currently I count from start to end, it shouldn't cause any problems as far as I can see but I'm not too familiar with it)...

Code: Select all

error: no matching function for call to 'std::vector<chunk*>::at(std::vector<chunk*>::iterator&)'
Yus, figured that would happen.
Can't see how raw access would make a difference, [] and .at() should behave the exact same except in terms of bounds checking

Code: Select all

error: no match for 'operator[]' (operand types are 'std::vector<chunk*>' and 'std::vector<chunk*>::iterator {aka __gnu_cxx::__normal_iterator<chunk**, std::vector<chunk*> >}')
Well, I figured that would happen.
I should get some more coffee before I even try to analyze what the hell is going on.
"this is not the bottleneck you are looking for"
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: allocation/deallocation issues [general C++/vectors]

Post by CuteAlien »

You somehow use 'at' with an iterator instead of an index (it needs an index). That's all I can say from the error message alone. You have to post the line for which you get the error as well as the declaration of all variables in that line or it's hard to tell more.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: allocation/deallocation issues [general C++/vectors]

Post by Seven »

been watching and trying to understand the issue. I use the lists regularly and am thinking maybe you dont want to use iterators for some reason? Would like to understand why though...

since the bool list never reserves pointer memory, the bool's dont need deleted
since the nodelist stores pointers to scenendoes, the scenenodes need to be freed

Code: Select all

 
 
list<bool> bList;   // declare the list
for (int x =0; x< 10; x++) bList.push_back(true);  // push 10 items onto the list
 
list<bool>::iterator it;   // create an iterator for the list
for (it=bList.begin(); it!=bList.end())  // from start to end 
{
    if (we_want_to_delete_the_bool) // i.e. if ( (*it) == true) 
        it = bList.erase(it);  // this is not a pointer it is just a bool value, so we dont need to delete it, just remove it from the list
     else it++; // otherwise, just increment the iterator to the next item in the list
}
 
or to simply clear the list completely
bList.clear();   // we can do this because the list does not hold pointers to anything, it just holds bool values
 
 
list<ISceneNode*> NodeList;  // declare the list
for (int x =0; x< 10; x++) NodeList->push_back(smgr->createCubeSceneNode(blah blah blah);  // push 10 scenenodes onto the list
 
list<ISceneNode*>::iterator it2;  // create an iterator for this type of list
for (it2=NodeList.begin(); it2!=NodeList.end())  // from start to end of the list
{
    if (we_want_to_delete_the_node) // i.e. if ( !(*it)->getVisible() )
    {
         delete( (*it2) );                    // this is a pointer so it needs deleted 
         it2 = NodeList.erase(it2);    // remove the list item
    }
    else it2++;  // otherwise increment the iterator to the next item int he list
}
 
or to clear the list completely
 
list<ISceneNode*>::iterator it2;
for (it2=NodeList.begin(); it2!=NodeList.end())
{
     delete( (*it2) );                  // this is a pointer so it needs deleted 
      it2 = NodeList.erase(it2);  // remove the list item and set the iterator
}
 
 
Last edited by Seven on Tue Apr 07, 2015 10:07 pm, edited 2 times in total.
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: allocation/deallocation issues [general C++/vectors]

Post by Seven »

example of how I use the lists and iterators....

Code: Select all

 
#pragma once
 
#include "CSUtils.h"
 
namespace CS
{
    typedef class CSLevel CSLevel;
    typedef class CSObject CSObject;
 
    class CSObjectManager
    {
    public:
        CSObjectManager()           { /* do nothing constructor */  CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::CSObjectManager()"); }
        virtual ~CSObjectManager()  { /* do nothing constructor */  CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::~CSObjectManager()"); }
 
        // set all variables to a known value
        virtual void initialize();
 
        // dual creation allows for better error handling
        virtual bool create();
 
        // cleanup whatever memory mess we made
        virtual bool cleanup();
 
        // frame functions 
        virtual void preFrame(const float &elapsedtime);
        virtual void frame(const float &elapsedtime);
        virtual void postFrame(const float &elapsedtime);
 
        // add / remove / retrieve Objects
        void addObject(CSObject* Object);
        void removeObject(CSObject* Object, bool destroy = false);
        void removeObject(int id, bool destroy = false);
        void destroyAllObjects();
 
        // get a pointer to the requested object
        CSObject* getObjectPointer(int id);
 
        // simple tree search
        CSObject* getNextObject(bool newsearch);
 
        // set up light / fog use
        virtual void setUseLight(bool value);
        virtual void setUseFog(bool value);
 
    private:
        // a small list of available levels
        list<CSObject*> m_Objects;
        list<CSObject*>::Iterator m_Iterator;
    };
 
} // end namespace
 
 

Code: Select all

 
#include "stdafx.h"
#include "CSObjectManager.h"
#include "CSObject.h"
 
namespace CS
{
    void CSObjectManager::initialize()
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::initialize()");
 
        // set all variables toa known value
        m_Objects.clear();
    }
 
    bool CSObjectManager::create()
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::create()");
 
        // everything went fine
        return true;
    }
 
    bool CSObjectManager::cleanup()
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::cleanup()");
 
        // destroy all of the Objects
        destroyAllObjects();
 
        // always return false from a cleanup function
        return false;
    }
 
    // called before each frame
    void CSObjectManager::preFrame(const float &elapsedtime)
    {
        // run through the list of objects and call the object's function
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            (*it)->preFrame(elapsedtime);
            it++;
        }
    }
 
    // called during each frame
    void CSObjectManager::frame(const float &elapsedtime)
    {
        // run through the list of objects and call the object's function
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            (*it)->frame(elapsedtime);
            it++;
        }
    }
 
    // called after each frame
    void CSObjectManager::postFrame(const float &elapsedtime)
    {
        // run through the list of objects and call the object's function
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            (*it)->postFrame(elapsedtime);
            it++;
        }
    }
 
    // add / remove / retrieve Objects
    void CSObjectManager::addObject(CSObject* Object)
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::addObject(%d)", Object->getId());
 
        // add it to the list
        m_Objects.push_back(Object);
    }
 
    void CSObjectManager::removeObject(CSObject* Object, bool destroy)
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::removeObject(%d)", Object->getId());
 
        // run through the list of obejcts
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            // if this is our object
            if ((*it) == Object)
            {
                // and we want to destroy it
                if (destroy)
                {
                    // clean it
                    (*it)->cleanup();
 
                    // delete it
                    delete(*it);
 
                    // and erase it from the list
                    it = m_Objects.erase(it);
 
                    // now bail
                    return;
                }
                else
                {
                    // just erase it from the list
                    it = m_Objects.erase(it);
 
                    // and then bail
                    return;
                }
            }
 
            // increment the iterator
            it++;
        }
    }
 
    void CSObjectManager::removeObject(int id, bool destroy)
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::removeObject(%d)", id);
 
        // run through the list of obejcts
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            // if this is our object
            if (((*it)->getId()) == id)
            {
                // and we want to destroy it
                if (destroy)
                {
                    // clean it
                    (*it)->cleanup();
 
                    // delete it
                    delete(*it);
 
                    // and erase it from the list
                    it = m_Objects.erase(it);
 
                    // now bail
                    return;
                }
                else
                {
                    // just erase it from the list
                    it = m_Objects.erase(it);
 
                    // and then bail
                    return;
                }
            }
            // increment the iterator
            it++;
        }
    }
 
    // cleanup, delete and remove all objects from the list
    void CSObjectManager::destroyAllObjects()
    {
        // log this event
        CS_LOG(CSL_DEBUG, "%s", "CSObjectManager::destroyAllObject()");
 
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            // clean it
            (*it)->cleanup();
 
            // delete it
            delete(*it);
 
            // and erase it from the list
            it = m_Objects.erase(it);
        }
    }
 
    // simple search through list and get a pointer to the requested obejct
    // return NULL if it does not exist in the list
    CSObject* CSObjectManager::getObjectPointer(int id)
    {
        list<CSObject*>::Iterator it;
        for (it = m_Objects.begin(); it != m_Objects.end();)
        {
            if (((*it)->getId()) == id) return (*it);
            it++;
        }
        return NULL;
    }
 
    // run through the list and return a pointer to each object
    // use like this
    // CSObject* obj = getNextObject(true);
    // while (obj)
    // {
    //     do whatever with the obejct (except delete it!)
    //      
    //     obj = getNextObject(false);
    // }
    CSObject* CSObjectManager::getNextObject(bool newsearch)
    {
        if (m_Objects.empty()) return NULL;
 
        if (newsearch)
        {
            m_Iterator = m_Objects.begin();
            return (*m_Iterator);
        }
 
        if (++m_Iterator == m_Objects.end())    return NULL; else return (*m_Iterator);
 
        return NULL;
    }
 
    // setup light use
    void CSObjectManager::setUseLight(bool value)
    {
        CSObject* obj = getNextObject(true);
        while (obj)
        {
            obj->setUseLight(value);
            obj = getNextObject(false);
        }
    }
 
    // setup fog use
    void CSObjectManager::setUseFog(bool value)
    {
        CSObject* obj = getNextObject(true);
        while (obj)
        {
            obj->setUseFog(value);
            obj = getNextObject(false);
        }
    }
} // end namespace
Post Reply