简体   繁体   中英

C++: make full copy of vector of pointers

I'm working on a C++ game. My level objects are in a vector (Object being a superclass for my level's objects).

I need the state of this vector to be saved at checkpoints, and retrieved at death.

So at the beginning of the level, the vector (objects) is created (old_objects).

If you hit a checkpoint, old_objects is erased and objects is re-copied to old_objects.

If you die, the data from objects is erased and old_objects is copied back to objects.

I've been trying to do this several ways but I'm not able to get it working. Help?

EDIT: I tried using a virtual clone() method. It throws out of range errors.

class Object {
  public:
    virtual Object* clone() { return new Object(); }
};

class SubObjectA {
  public:
    Object* clone() { return new SubObjectA(datablahblah); }
};

class SubObjectB {
  public:
    Object* clone() { return new SubObjectB(datablahblah); }
};

for (vector<Object*>::iterator it = objects.begin(); it != objects.end(); it++) {
    Object* tempobj = *it;
    old_objects.push_back(tempobj->clone());
}

But all I get is the same old:

terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

You could use the Prototype pattern and have your Object base class declare a pure virtual clone() method. Then at checkpoint time you just have to iterate over the vector calling clone on the pointers and pushing them into the new vector.

The only important requirement here is to provide a deep copy constructor that stores all necessary information (or if that's not possible, a method to get all the required info). Then use that ctor/method to create a second vector. Something like:

class Object
{
    RenderObject * m_Renderable;
    int m_Health;
    float3 m_Position;

    Object(const Object * other) :
       m_Renderable(nullptr),
       m_Health(other->m_Health), 
       m_Position(other->m_Position)
    { };

    Object * GetStorable()
    {
        return new Object(*this);
    }
};

then to store "checkpoints", you simply do:

vector<vector<shared_ptr<Object>>> gCheckpoints;
vector<shared_ptr<Object>> gLevelObjects;

vector<shared_ptr<Object>> checkpoint;
std::for_each(
    gLevelObjects.begin(), gLevelObjects.end(),
    [&](shared_ptr<Object> obj)
    {
        checkpoint.push_back(obj->GetStorable());
    });
gCheckpoints.push_back(checkpoint); // creates a new checkpoint

You will need to recreate the render information for the objects when the checkpoint is restored; this is a requirement for most save systems in most graphics contexts, however.

Depending on how your Object class is set up, you can also inherit from another class that consists only of the stored data, and simply store that and create the renderables from it when necessary ( class RenderObject : StoredObject { ... }; ).

You can alternatively serialize the objects in some fashion (binary save, xml, json) and store that to a file (autosave/quicksave/checkpoint) or in-memory, and then use your regular loading mechanism to load that specific file.

The best method depends on what your plans are and how your system is set up, but this concept should provide the basics or give you a starting point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM