Есть ли способ в C ++ сохранить объект, а затем перезагрузить его, хотя у него есть указатель в качестве атрибута? - PullRequest
1 голос
/ 04 апреля 2020

У меня есть объект, у которого есть этот указатель 'SDL_Texture * texture' и, конечно, некоторые другие нерелевантные атрибуты и методы. Я хотел сохранить весь объект в файл, а затем перезагрузить его в следующем сеансе. Я попытался загрузить его и переназначить текстуру (которая указала бы на неправильный адрес памяти) перед ее использованием, но, конечно, я получаю совершенно неправильные значения. Вот код:

class Entity
{
private:
    SDL_Texture *texture = NULL;
    // ...
public:
    Entity::Entity(){}
    void Entity::loadSprites()
    {
        this->texture = IMG_Load("./sprites/puppet/idle.png");
        // ...
    }
}

Entity load(const char filepath[])
{
    Entity ent;
    ifstream file(filepath);
    file.read(reinterpret_cast<char*>(&ent), sizeof(Entity));
    file.close();
    ent.loadTexture();
    return ent;
}

Я знаю, что идея загрузки неправильного указателя, вероятно, одна из худших вещей, которые я могу сделать, но мне было интересно, как это может изменить значения каждого атрибута моего объекта, и как я могу избежать этого. Я также должен признать, что я не совсем понимаю, как работает reinterpret_cast (& ent).

1 Ответ

3 голосов
/ 04 апреля 2020

Проблема, которую вы описываете, связана с сериализацией данных. В этом процессе вы записываете все необходимые данные в поток данных, чтобы вы могли восстановить внутреннее состояние объекта из этих данных позже. Вы обычно хотите написать минимум необходимых данных. go Есть много способов, как это реализовать:

  • Создать save(std::ostream & data) функцию-член и определить конструктор: Entity(std::istream & data), который создает объект из данных, прочитанных из потока.
  • Использовать библиотеку сериализации, такую ​​как boost :: serialization (очень обобщенно c, можно (де) сериализовать что угодно )

В любом случае вам необходимо выбрать формат данных: объект, так что вы можете надежно прочитать его. Просто выгрузить весь объект на диск с помощью fstream :: write () / read () - плохая идея по многим причинам:

  • Объекты могут содержать некоторые указатели, такие как vtable, которые нельзя сохранить. Они фиксируются на месте в конструкторе.
  • Если класс будет каким-либо образом изменен после сброса данных, он сделает ненужными уже сохраненные данные.
  • Запись любых значений адресов данных в файл является ошибкой : при следующем запуске программы они недействительны. Любые указатели на данные должны быть сериализованы (сами данные, а не указатель!)
  • Сериализация обычно является рекурсивным процессом. Например, boost :: serialization обрабатывает это, так что вы можете сериализовать такие вещи, как контейнеры объектов. (например, std :: list)
...