shared_ptr 的引入导致反序列化时出现分段错误(使用 boost::serialization)
Introduction of shared_ptr leads to a segmentation fault upon deserialization (with boost::serialization)
我有一个class伽马,如下图。
当 make_nvp 函数尝试反序列化现有 xml 文件时,加载函数会引发分段错误。当我使用 std::shared_ptr<std::tuple<double,double,double>> val;
时出现错误
如果 val 只是 std::tuple<double,double,double> val;
然后似乎一切正常(当然,我相应地更改了 getter 和 setter 函数)。
现在我复习了一堆关于 Whosebug 的问题,我用谷歌搜索并查看了 boost 文档中的示例,但我不明白为什么加载函数会导致程序因分段错误而终止。
注意: 互联网上的一些旧帖子(以及 Whosebug 上的一些旧问题)似乎暗示 std::shared_ptr 过去在那个时候不能使用 boost 序列化及时。我不认为 2017 年会出现这种情况。无论如何,为了确定,我尝试用 boost::shared_ptr 替换 std::shared_ptr 并且分段错误仍然存在。
我不会understand/see为什么会出现这个错误?
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());
}
shared_ptr 实际上可以添加到内部的单个元组中……对我来说是个谜。但无论如何,我使您的代码独立并且有效:
我希望你能弄清楚你做了哪一部分differently/wrong:
#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>
我有一个class伽马,如下图。
当 make_nvp 函数尝试反序列化现有 xml 文件时,加载函数会引发分段错误。当我使用 std::shared_ptr<std::tuple<double,double,double>> val;
如果 val 只是 std::tuple<double,double,double> val;
然后似乎一切正常(当然,我相应地更改了 getter 和 setter 函数)。
现在我复习了一堆关于 Whosebug 的问题,我用谷歌搜索并查看了 boost 文档中的示例,但我不明白为什么加载函数会导致程序因分段错误而终止。
注意: 互联网上的一些旧帖子(以及 Whosebug 上的一些旧问题)似乎暗示 std::shared_ptr 过去在那个时候不能使用 boost 序列化及时。我不认为 2017 年会出现这种情况。无论如何,为了确定,我尝试用 boost::shared_ptr 替换 std::shared_ptr 并且分段错误仍然存在。
我不会understand/see为什么会出现这个错误?
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());
}
shared_ptr 实际上可以添加到内部的单个元组中……对我来说是个谜。但无论如何,我使您的代码独立并且有效:
我希望你能弄清楚你做了哪一部分differently/wrong:
#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>