【问题标题】:C++ Boot serialization cause a segmentation faultC++ 引导序列化导致分段错误
【发布时间】:2021-06-11 11:18:32
【问题描述】:

我有这两个类,我正在尝试使用 boost 反序列化它们

class WorldItem
{
private:
    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar &foreground;
        ar &background;
        ar &breakLevel;
        ar &breakTime;
        ar &water;
        ar &fire;
        ar &glue;
        ar &red;
        ar &green;
        ar &blue;
    }

public:
    int foreground = 0;
    int background = 0;
    int breakLevel = 0;
    long long int breakTime = 0;
    bool water = false;
    bool fire = false;
    bool glue = false;
    bool red = false;
    bool green = false;
    bool blue = false;
};

class Worlds
{
private:
    friend class boost::serialization::access;
    template <class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar &width;
        ar &height;
        ar &name;
        for (int i = 0; i < 100 * 60; i++)
        {
            ar &items[i];
        }
        ar &owner;
        ar &weather;
        ar &isPublic;
        ar &isNuked;
    }

public:
    int width;
    int height;
    string name;
    WorldItem *items;
    string owner = "";
    int weather = 0;
    bool isPublic = false;
    bool isNuked = false;
};

我正在以这种方式创造一个世界

Worlds generateWorld(string name, int width, int height)
{
    Worlds world;
    world.name = name;
    world.width = width;
    world.height = height;
    world.items = new WorldItem[100 * 60];
 }

这里我使用这个函数来序列化世界

std::stringstream serialize_world(Worlds world)
{
    std::stringstream str;
    {
        boost::archive::binary_oarchive oa(str);
        oa << world;
    }
    return str;
}

所以 serialize_world 函数可以正常工作,我将其值插入 mysql longblob。

但是现在当我尝试从 MySql 中获取 blob 并使用此函数将其反序列化时

Worlds deserialize(std::string world)
{

    Worlds wld;
    std::istream *blobdata = WORLD_DATA(world);
    {
    boost::archive::binary_iarchive ia(*blobdata);
    ia >> wld;
    }
    return wld;
}

我遇到了分段错误(核心转储)我不知道出了什么问题。

谢谢。

【问题讨论】:

    标签: c++ c++11 boost boost-serialization


    【解决方案1】:

    看起来您从未从 generateWorld 返回值。

    我的编译器对此发出警告。尝试启用编译器的诊断。我通常启用-Wall -Wextra -pedantic

    同样在deserialize 中,你永远不会将items 初始化为任何东西。这将导致UB

    大多数编译器也可以诊断出这一点(-fsanitize=address,undefined 有帮助,尽管它会使编译和运行时变慢)。还有像 Valgrind 这样的外部工具可以做到这些

    最后,我不知道blobdata 发生了什么,所以我将忽略它,但它看起来也有问题。

    不要使用原始的 new/delete

    参见例如https://www.quora.com/Why-are-the-%E2%80%98new%E2%80%99-and-%E2%80%98delete%E2%80%99-keywords-considered-bad-in-modern-C++

    然后使用std::array 并开心:

    Live On Coliru

    #include <boost/archive/binary_iarchive.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/serialization.hpp>
    #include <boost/serialization/array.hpp>
    #include <array>
    #include <iostream>
    #include <sstream>
    
    class WorldItem {
      private:
        friend class boost::serialization::access;
        template <class Ar> void serialize(Ar& ar, unsigned) {
            ar& foreground& background& breakLevel& breakTime& water& fire& glue&
                red& green& blue;
        }
    
      public:
        int foreground          = 0;
        int background          = 0;
        int breakLevel          = 0;
        long long int breakTime = 0;
        bool water              = false;
        bool fire               = false;
        bool glue               = false;
        bool red                = false;
        bool green              = false;
        bool blue               = false;
    
        auto operator<=>(WorldItem const&) const = default;
    };
    
    class Worlds
    {
      private:
        friend class boost::serialization::access;
        template <class Ar> void serialize(Ar& ar, unsigned) {
            ar& width& height& name& items& owner& weather& isPublic& isNuked;
        }
    
      public:
        int width;
        int height;
        std::string name;
    
        std::array<WorldItem, 100 * 60> items;
        std::string owner = "";
        int weather       = 0;
        bool isPublic     = false;
        bool isNuked      = false;
    
        auto operator<=>(Worlds const&) const = default;
    };
    //So here im creating a world in this way
    
    Worlds generateWorld(std::string name, int width, int height) {
        Worlds world;
        world.name   = name;
        world.width = width;
        world.height = height;
        return world;
    }
    
    std::string serialize_world(Worlds const& world) {
        std::stringstream str;
        {
            boost::archive::binary_oarchive oa(str);
            oa << world;
        }
        return str.str();
    }
    
    Worlds deserialize(std::string world) {
        Worlds wld;
        std::istringstream blobdata(world);
        {
            boost::archive::binary_iarchive ia(blobdata);
            ia >> wld;
        }
        return wld;
    }
    
    int main() {
        Worlds w = generateWorld("test", 6, 6);
    
        Worlds clone = deserialize(serialize_world(w));
    
        std::cout << "Worlds equal? " << std::boolalpha << (w == clone) << "\n";
    }
    

    打印

    Worlds equal? true
    

    【讨论】:

    • 好吧,我使用了你发送给我的内容,std::array 实际上帮助了我,但由于某种原因,在抛出 'boost::archive::archive_exception' what() 的实例后,我仍然收到此错误终止调用:反序列化后输入流错误中止(核心转储)
    • 更新成功了,非常感谢你帮助我,我真的很感激
    • @cmdocmd 干杯。欢迎来到Stack Overflow。还请考虑解决您问题的accepting 答案。添加了一些关于如何自行查找此类问题的说明
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-25
    • 1970-01-01
    相关资源
    最近更新 更多