在反序列化时引入shared_ptr会导致分段错误(使用boost :: serialization)

时间:2017-03-03 15:00:12

标签: c++ serialization boost deserialization shared-ptr

我有一个类伽玛,如下所示。

当make_nvp函数尝试反序列化现有的xml文件时,load函数会抛出分段错误。使用std::shared_ptr<std::tuple<double,double,double>> val;

时会出现错误

如果val只是std::tuple<double,double,double> val;

然后一切似乎都运行正常(当然,我相应地更改了getter和setter函数)。

现在我回顾了一堆关于stackoverflow的问题,我用Google搜索并查看了boost文档中的示例,我无法弄清楚,为什么加载函数会导致程序以分段错误终止。

注意:互联网上的一些旧帖子(以及一些关于stackoverflow的旧问题)似乎暗示std :: shared_ptr过去常常无法使用boost序列化。我不认为2017年就是这种情况。无论如何,只是为了确定,我尝试用boost :: shared_ptr替换std :: shared_ptr并且分段错误仍然存​​在。

我不明白/看到错误出现的原因?

gamma.h

#pragma once
#include <map>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <tuple>

namespace boost
{
    namespace serialization
    {
        template<typename Archive>
        void serialize(Archive & ar, std::tuple<double, double, double> & t,
                    const unsigned int version)
        {
            ar & boost::serialization::make_nvp("t0",std::get<0>(t));
            ar & boost::serialization::make_nvp("t1",std::get<1>(t));
            ar & boost::serialization::make_nvp("t2",std::get<2>(t));
        }

    }
}

class Gamma
{
public:
    static void save(std::ostream& os);
    static void load(std::istream& is);

    std::shared_ptr<std::tuple<double, double, double>> getterX() const;
    void setterX(const std::tuple<double, double, double> &val);

private:

    std::shared_ptr<std::tuple<double,double,double>> val;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& arc, const unsigned int version)
    {
          arc & boost::serialization::make_nvp("val", val);
    }
};

和gamma.cpp

#include "gamma.h"
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>

Gamma &Gamma::instance()
{
    static Gamma obj;
    return obj;
}

std::shared_ptr<std::tuple<double, double, double>> Gamma::getterX() const
{
    return val;
}

void Gamma::setterX(const std::tuple<double, double,double> &v)
{
    if (nullptr == val) {
        m_touchDownCalibration = std::make_shared<std::tuple<double, double,double>>();
    }
    *val = v;
}

const char* TAG = "tag";

void Gamma::save(std::ostream& os)
{
    boost::archive::xml_oarchive arc(os);
    arc & boost::serialization::make_nvp(TAG,instance());
}

void Gamma::load(std::istream& is)
{
    boost::archive::xml_iarchive arc(is);
    arc & boost::serialization::make_nvp(TAG,instance());
}

1 个答案:

答案 0 :(得分:1)

对我来说,一个神秘的东西是shared_ptr实际上可以添加到单个元组里面......一个单身人士。但无论如何,我使你的代码自成一体并且有效:

<强> Live On Coliru

我希望你能弄清楚你做出哪些不同/错误的部分:

#include <map>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <tuple>

namespace boost { namespace serialization {
    template<typename Archive>
    void serialize(Archive & ar, std::tuple<double, double, double> & t, unsigned) {
        ar & boost::serialization::make_nvp("t0", std::get<0>(t));
        ar & boost::serialization::make_nvp("t1", std::get<1>(t));
        ar & boost::serialization::make_nvp("t2", std::get<2>(t));
    }
} }

class CalibrationDataObject
{
public:
    static CalibrationDataObject &instance();
    static void save(std::ostream& os);
    static void load(std::istream& is);

    std::shared_ptr<std::tuple<double, double, double>> getterX() const;
    void setterX(const std::tuple<double, double, double> &val);

private:
    std::shared_ptr<std::tuple<double,double,double>> val;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& arc, unsigned)
    {
          arc & boost::serialization::make_nvp("val", val);
    }
};

//#include "CalibrationDataObject.h"
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>

CalibrationDataObject &CalibrationDataObject::instance() { static CalibrationDataObject obj; return obj; }

std::shared_ptr<std::tuple<double, double, double>> CalibrationDataObject::getterX() const {
    return val;
}

void CalibrationDataObject::setterX(const std::tuple<double, double,double> &v)
{
    if (val)
        *val = v;
    else 
        val = std::make_shared<std::tuple<double, double,double>>(v);
}

const char* TAG = "tag";

void CalibrationDataObject::save(std::ostream& os)
{
    boost::archive::xml_oarchive arc(os);
    arc & boost::serialization::make_nvp(TAG,instance());
}

void CalibrationDataObject::load(std::istream& is)
{
    boost::archive::xml_iarchive arc(is);
    arc & boost::serialization::make_nvp(TAG,instance());
}

#include <fstream>

int main() {
    {
        std::ofstream ofs("test.data");
        CalibrationDataObject::save(ofs);
    }
    {
        std::ifstream ifs("test.data");
        CalibrationDataObject::load(ifs);
    }
}

打印以下数据:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="14">
<tag class_id="0" tracking_level="0" version="0">
    <val class_id="1" tracking_level="0" version="1">
        <px class_id="-1"></px>
    </val>
</tag>
</boost_serialization>