Поток ввода широкого символа std::wifstream повреждается при десериализации объекта, который был сериализован с использованием std::wofstream

Я пытаюсь написать свою собственную сериализацию и десериализацию для объекта моего приложения. Я знаю, что существует множество библиотек, таких как ускоренная сериализация и т. д., доступных для готового использования, но я хотел изучить эту сериализацию и десериализацию, следовательно, это усилие.

Проблема возникает, когда я пытаюсь десериализовать (используя std::wifstream) объект, который я сериализовал (используя std::wofstream). Не в состоянии прочитать даже одного члена класса правильно. Первые 3 члена, которые я пытаюсь десериализовать, являются логическими, но они считывают неверные значения из файлового потока. Может кто-нибудь, пожалуйста, предложите какие-либо указатели относительно того, что может быть проблемой здесь. Спасибо за ваше время.

Typedefs в приложении:

namespace fc
{
#ifdef UNICODE
    typedef std::wstring tstring;
    typedef std::wfstream tfstream;
    typedef std::wofstream tofstream;
    typedef std::wifstream tifstream;
    typedef std::wstringstream tstringstream;
#else
    typedef std::string tstring;
    typedef std::fstream tfstream;
    typedef std::ofstream tofstream;
    typedef std::ifstream tifstream;
    typedef std::stringstream tstringstream;
#endif

    typedef std::vector<fc::tstring> tstrvec;
    typedef std::vector<fc::tstring> tstrvec;
}

Объект сериализуется и десериализуется:

struct FastCopyCfg
{
    bool mOverwriteFiles;
    bool mCopySystemFiles;
    bool mCopyHiddenFiles;
    fc::tstring mDstFolder;
    fc::tstrvec mSrcFiles;
    fc::tstrvec mSrcFolders;
    fc::tstrvec mIncludeWildcards;
    fc::tstrvec mExcludeWildcards;

    FastCopyCfg()
    {
        mOverwriteFiles = false;
        mCopySystemFiles = false;
        mCopyHiddenFiles = false;
        mDstFolder.clear();
        mSrcFiles.clear();
        mSrcFolders.clear();
        mIncludeWildcards.clear();
        mExcludeWildcards.clear();
    }

    template<typename Archive>
    void Serialize(Archive& ar, const std::uint16_t = 0)
    {
        ar & mCopySystemFiles & mCopyHiddenFiles & mOverwriteFiles &
            mDstFolder & mSrcFiles & mSrcFolders & mIncludeWildcards & mExcludeWildcards;
    }
};

Глобальные операторы вставки и извлечения перегружены:

void operator >>(IArchive& ar, FastCopyCfg& cfg)
{
    cfg.Serialize(ar);
}

void operator <<(OArchive& ar, FastCopyCfg& cfg)
{
    cfg.Serialize(ar);
}

Классы архиваторов

class OArchive
{
    std::wostream& mStream;

public:
    OArchive(std::wostream& stream) :mStream(stream){}

    template<typename Val>
    OArchive& operator &(std::vector<Val>& vtr)
    {
        mStream << vtr.size();
        std::for_each(vtr.begin(), vtr.end(), [&](auto e) {mStream << e; });
        return *this;
    }

    template<typename DT>
    OArchive& operator &(DT& data)
    {
        mStream << data;
        return *this;
    }
};

class IArchive
{
    std::wistream& mStream;

public:
    IArchive(std::wistream& stream) :mStream(stream) {}

    template<typename Val>
    IArchive& operator &(std::vector<Val>& vtr)
    {
        std::vector<Val>::value_type vElement;
        std::vector<Val>::size_type vSize = 0;

        mStream >> vSize;
        for (std::vector<Val>::size_type i = 0; i < vSize; i++)
        {
            mStream >> vElement;
            vtr.push_back(vElement);
        }
        return *this;
    }

    template<typename DT>
    IArchive& operator &(DT& data)
    {
        try
        {
            mStream >> data;
        }
        catch (const std::exception& e)
        {
            Logger::logDebug("Exception while reading config file: ", e.what());
        }
        catch (...)
        {
        }
        return *this;
    }
};

Сериализация с помощью кода. Я устанавливаю флаг в значение true и false для отладки сериализации и десериализации.

bool flag = false;
void CFastCopyDlg::OnBnClickedButtonSaveConfiguration()
{
    if (flag)
    {
        fc::tofstream file(fc::CONFIG_FILENAME, fc::tofstream::binary);
        OArchive ar(file);
        ar << getCopyConfig();
    }
    else
    {
        fc::tifstream file(fc::CONFIG_FILENAME, fc::tifstream::binary);
        IArchive ar(file);
        FastCopyCfg cfg;
        ar >> cfg;
    }
}

person Anand    schedule 05.06.2021    source источник
comment
Опубликуйте минимально воспроизводимый пример. Если проблема в десериализации, это не имеет ничего общего с нажатиями кнопок. Простой класс, возможно, с одним логическим значением и одним std::wstring с жестко запрограммированными значениями, с 3- или 4-строчной функцией main, которая просто сериализует и десериализует простую структуру. Затем используйте отладчик для отладки этого простого кода, чтобы изолировать проблему (и, возможно, даже выяснить, в чем проблема). Прямо сейчас вы загромождаете вещи аспектами программы, которые не важны для решения проблемы.   -  person PaulMcKenzie    schedule 06.06.2021
comment
Кроме того, неразумно писать весь этот код и не знать, каким будет окончательный результат использования этой библиотеки сериализации. Вы должны были начать с чего-то простого (как указано в моем первом комментарии), просто чтобы проверить.   -  person PaulMcKenzie    schedule 06.06.2021
comment
Вы записываете все строки в векторе одну за другой без разделителей. Как вы надеетесь снова разделить их при чтении? Если на то пошло, предположим, что у вас есть вектор с одной строкой "23a". Код сериализации создаст фрагмент текста 123a (размер 1 сразу за строкой). При обратном разборе вы прочитаете 123 в размер, а затем попытаетесь прочитать 123 строки.   -  person Igor Tandetnik    schedule 06.06.2021


Ответы (1)


Я думаю, что нашел проблему. Проблема в том, что десериализация с использованием любого std fstream, когда файл открыт в двоичном режиме, НЕ МОЖЕТ быть выполнена с использованием оператора извлечения ››. Подобная тема обсуждалась ЗДЕСЬ. Пожалуйста, обратитесь к приведенному ниже коду, чтобы увидеть, где проблема существовала в коде вопроса.

class IArchive
{
    std::wistream& mStream;

public:
    IArchive(std::wistream& stream) :mStream(stream) {}

    template<typename Val>
    IArchive& operator &(std::vector<Val>& vtr)
    {
        std::vector<Val>::value_type vElement;
        std::vector<Val>::size_type vSize = 0;

        mStream >> vSize;
        for (std::vector<Val>::size_type i = 0; i < vSize; i++)
        {
            mStream >> vElement;
            vtr.push_back(vElement);
        }
        return *this;
    }

    template<typename DT>
    IArchive& operator &(DT& data)
    {
        try
        {
            mStream >> data; // PROBLEM - BINARY DATA CANNOT BE READ USING >>
        }
        catch (const std::exception& e)
        {
            Logger::logDebug("Exception while reading config file: ", e.what());
        }
        catch (...)
        {
        }
        return *this;
    }
};
person Anand    schedule 06.06.2021