简体   繁体   中英

How to load content of a const variable from a file?

What is the method to save and retrieve contents (to/from a disk file) of an object who has const member variables?
Or more specifically, const members demand an initialization at the creation time of the object. So, the retrieval of the content has to happen before the initializers (before { } of the constructor). If we are not minding the encapsulation, we can retrieve and create the object with parameters. How to do everything by keeping the data-hiding?


Compiler: C++ 14 and maybe beyond.


Instantiation of the object, filling the content and storing for next context.

    { //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();
    }

using same object after taking from file.

    { //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);
        }
    }

The class.

#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;
   }
};

Please suggest a better method. For this, I have introduced a 'healthy' status member as the first member in the declaration of the class. Also in deserialization, I am fooling the compiler by casting the const variable to char * pointer.

My suggestion will be to use a static member function of the class to retrieve the contents of the file from disk and construct an object after the contents have been retrieved successfully.

Instead of:

 Abcd(QFile &src) :

Use

static Abcd deserialize(QFile& src);

and implement it as:

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 It's strange that you save _rY first and then _rX . There is nothing wrong, it's just strange.

My suggestion is to split up the logic of Abcd and serialization/deserialization into two classes.

Benefits:

  • no field _healthy as object is always valid by design.
  • class Abcd does only one job. Is free from any logic of storing (Single responsibility)

Few hints:

  • RVO is mandatory since c++ 17
  • const fields just make the object not copy/move assignable (unable to use with containers etc.). Simply properly use const correctness to ensure immutability.
  • do not inherit implementation, only interfaces: Abcd is final, no virtual methods - better performance.
  • follow the 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;
};

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