Как загрузить содержимое переменной const из файла? - PullRequest
0 голосов
/ 22 февраля 2019

Каков метод для сохранения и извлечения содержимого (в / из файла на диске) объекта, который имеет переменные-члены с постоянными значениями?
Или, более конкретно, члены-константы требуют инициализации при созданиивремя объекта.Таким образом, извлечение содержимого должно происходить до инициализаторов (до {} конструктора).Если мы не возражаем против инкапсуляции, мы можем извлечь и создать объект с параметрами.Как сделать все, сохранив скрытие данных?


Компилятор: C ++ 14 и, возможно, не только.


Создание объекта, заполнение содержимого и сохранение для следующего контекста.

    { //CODE BLOCK 1 : making of content and saving to a diskfile
        Abcd abcd(65535,256,25);
        //some operations on abcd
        //save to disk
        QFile abcdFile("abcd.lion");
        abcdFile.open(QFile::WriteOnly);
        abcd.serialize(abcdFile);
        abcdFile.close();
    }

с использованием того же объекта после извлечения из файла.

    { //CODE BLOCK 2 : loading from file and continue in another context
        QFile abcdFile("abcd.lion");
        abcdFile.open(QFile::ReadOnly);
        Abcd abcdNew(abcdFile);
        abcdFile.close();
        if(!abcdNew.isHealthy())
            printf("abcd from hdd is NOT Healthy :(\n");
        else
        {
            //doTheJob(abcdNew);
        }
    }

Класс.

#include <QFile>
class Abcd
{
    const bool _healthy;//true if properly initialized
    //IMPORTANT: _healthy has to be the first member in the class.
    //this is to execute its initializer list first
protected:
    const long _rX;
    const long _rY;
          long _count;
public:
    Abcd(const long refX,
         const long refY,
         const long count) :
        _healthy(true),
        _rX(refX), _rY(refY),
        _count(count)
    {

    }
    Abcd(QFile &src) :
        _healthy(deserialize(src)),
        //Hack. Actually the initialization happened by this statement.
        //just keeping the below statements for the sake of syntactical correctness. :(
        _rX(_rX), _rY(_rY)
        //,_count(count)
    {

    }
    virtual
    ~Abcd()
    {

    }
    inline
    bool isHealthy()
    {
        return _healthy;
    }
    bool serialize(QFile &dest)
    {
        if(dest.write((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
        if(dest.write((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
        if(dest.write((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
        return true;
    }
private:
    bool deserialize(QFile &src)
    {
        if(src.read((char *)&_rY,sizeof(_rY))!=sizeof(_rY)) return false;
        if(src.read((char *)&_rX,sizeof(_rX))!=sizeof(_rX)) return false;
        if(src.read((char *)&_count,sizeof(_count))!=sizeof(_count)) return false;
        return true;
   }
};

Пожалуйста, предложите лучший метод.Для этого я ввел «здоровый» член статуса в качестве первого члена в объявлении класса.Также в десериализации я обманываю компилятор, приводя переменную const к указателю char *.

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Я предлагаю разделить логику Abcd и сериализации / десериализации на два класса.

Преимущества:

  • без поля _healthy, так как объект всегда действителен по замыслу.
  • класс Abcd выполняет только одну работу.Свободен от какой-либо логики хранения (Единственная ответственность)

Несколько подсказок:

  • RVO является обязательным, поскольку поля c ++ 17
  • const просто создаютобъект не может быть скопирован / перемещен (не может использоваться с контейнерами и т. д.).Просто правильно используйте constкорректность, чтобы обеспечить неизменность.
  • не наследуют реализацию, только интерфейсы: Abcd является окончательным, нет виртуальных методов - лучшая производительность.
  • следуйте Cpp Core Guidelines
class Abcd final
{
public:
    Abcd(const long refX, const long refY, const long count)
        : _rX(refX)
        , _rY(refY)
        , _count(count)
    {
    }

    long GetRX() const
    {
        return _rX;
    }

    long GetRY() const
    {
        return _rY;
    }

    long GetCount() const
    {
        return _count;
    }

protected:
    long _rX;
    long _rY;
    long _count;
};
#include <boost/optional.hpp>
#include <QFile>

template <typename T>
using Opt = boost::optional<T>; // or equivalent

// Choose better name for Serializer or even split it up
class AbcdSerializer final
{
public:
    AbcdSerializer(QFile& file)
        : _file(file)
    {
    }

    // You may also throw an exception instead of returning optional
    Opt<Abcd> TryDeserializeAbcd()
    {
        long rX;
        long rY;
        long count;

        if (ReadValue(rY) && ReadValue(rX) && ReadValue(count))
        {
            return Abcd(rX, rY, count);
        }

        return {};
    }

    bool SerializeAbcd(const Abcd& abcd)
    {
        return WriteValue(abcd.GetRY()) && WriteValue(abcd.GetRX()) && WriteValue(abcd.GetCount());
    }

private:
    template <typename T>
    bool ReadValue(T& value)
    {
        constexpr auto ValueSize = sizeof(value);

        return _file.read(reinterpret_cast<char*>(&value), ValueSize) != ValueSize;
    }

    template <typename T>
    bool WriteValue(const T& value)
    {
        constexpr auto ValueSize = sizeof(value);

        return _file.write(reinterpret_cast<const char*>(&value), ValueSize) != ValueSize;
    }

    QFile& _file;
};
0 голосов
/ 22 февраля 2019

Мое предложение будет состоять в использовании static функции-члена класса для извлечения содержимого файла с диска и создания объекта после успешного извлечения содержимого.

Вместо:

 Abcd(QFile &src) :

Используйте

static Abcd deserialize(QFile& src);

и реализуйте его как:

Abcd Abcd::deserialize(QFile& src)
{
   long rX;
   long rY;
   long count;

   if(src.read((char *)&rY, sizeof(rY)) != sizeof(rY)) throw false;
   if(src.read((char *)&rX, sizeof(rX)) != sizeof(rX)) throw false;
   if(src.read((char *)&count, sizeof(count)) != sizeof(count)) throw false;

   return Abcd(rX, rY, count):
}

PS Странно, что сначала вы сохраняете _rY, а затем _rX.В этом нет ничего плохого, просто странно.

...