如何用C++解决JSON序列化错误?

roejwanj  于 2023-05-20  发布在  其他
关注(0)|答案(2)|浏览(154)

我在尝试使用JSON序列化类时遇到了以下运行时错误:
libc++abi: terminating with uncaught exception of type cereal::RapidJSONException: rapidjson internal assertion failure: IsObject()
有趣的是,完全相同的代码适用于二进制归档。
我正在尝试为我的代码创建一个模板函数。就像这样:

enum SER_Archive_Type {BIN, JSON};

template<typename T>
bool SerializeObject(T &obj, std::string filename, const SER_Archive_Type TYPE) {
    std::fstream fs;

    switch (TYPE) {
    case JSON: {
        fs.open(filename, std::ios::out);
        if (fs.is_open()) {
            cereal::JSONOutputArchive jarchive(fs);
            jarchive(obj);
            fs.close();
            return true;
        } else {
            return false;
        }
        break;
    }
    case BIN: {
        fs.open(filename, std::ios::out | std::ios::binary);
        if (fs.is_open()) {
            cereal::BinaryOutputArchive barchive(fs);
            barchive(obj);
            fs.close();
            return true;
        } else {
            return false;
        }
        break;
    }
    default: 
        break;
    }

    return false;
}

template<typename T>
bool DeserializeObject(T &obj, std::string filename, const SER_Archive_Type TYPE) {
    std::fstream fs;

    switch (TYPE) {
    case JSON: {
        fs.open(filename, std::ios::in);
        if (fs.is_open()) {
            cereal::JSONInputArchive jarchive(fs);
            jarchive(obj);
            fs.close();
            return true;
        } else {
            return false;
        }
        break;
    }
    case BIN: {
        fs.open(filename, std::ios::in | std::ios::binary);
        if (fs.is_open()) {
            cereal::BinaryInputArchive barchive(fs);
            barchive(obj);
            fs.close();
            return true;
        } else {
            return false;
        }
        break;
    }
    default: 
        break;
    }

    return false;
}

示例代码如下所示:

int main()
{
    uint32_t a = 123;
    SerializeObject(a, "a.bin", BIN);   // ok

    uint32_t b;
    DeserializeObject(b, "a.bin", BIN); // ok
    cout << b << endl; 

    uint32_t c = 321;
    SerializeObject(c, "c.txt", JSON);   // ok

    uint32_t d;
    DeserializeObject(d, "c.txt", JSON); // error
    cout << b << endl;
}

我发现生成的JSON文件中的顶层节点没有关闭。从示例中查看c.txt文件的内容:

{
    "value0": 321

这一定是不正确的行为,或者我错过了什么?我不知道如何正确解决这个问题。提前感谢您的帮助!

ybzsozfc

ybzsozfc1#

寿命问题可以更容易地解决:

if (std::ofstream file{filename}) 
    //file belongs to `if` scope: no need to close.
    cereal::JSONOutputArchive{file}(obj);
    /*Archive is rvalue and is destructed
    immediately if not captured by a reference.*/

注意:因为我使用ofstream而不是fstream,所以ios_base::out标志是多余的。对于输入文件,也可以使用ifstream。二进制文件仍然需要ios_base::binary

if (std::ofstream file{filename, std::ios_base::binary})...
llmtgqce

llmtgqce2#

显然,我还不明白档案室是怎么运作的。解决方案如下:

case JSON: {
        fs.open(filename, std::ios::out);
        if (fs.is_open()) { 
            { // to finish json inside of brackets and call destructor... 
                cereal::JSONOutputArchive jarchive(fs);
                jarchive(obj);
            }
            fs.close();
            return true;
        } else {
            return false;
        }
        break;
    }

相关问题