提高std的stl集合的序列化unique_ptrs [英] boost serialization of stl collection of std unique_ptrs

查看:58
本文介绍了提高std的stl集合的序列化unique_ptrs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够序列化std :: unique_ptrs的stl容器.能做到吗 顺便说一句,使用单个std :: unique_ptr一切都可以正常工作. 下面是我正在处理的代码,而gcc给出了以下错误:

I'd like to be able to serialize stl container of std::unique_ptrs. Can it be done? btw, everything works fine with single std::unique_ptr. Below is the code I'm working on, and the gcc gives the folowing error:

 use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const
 std::unique_ptr<_Tp, _Dp>&) [with _Tp = MyDegrees; _Dp =
 std::default_delete<MyDegrees>; std::unique_ptr<_Tp, _Dp> =
 std::unique_ptr<MyDegrees>]’

如何使代码正常工作?

#include <iostream>
#include <memory>
#include <fstream>
#include <map>
#include <vector>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
namespace boost {
namespace serialization {

template<class Archive, class T>
inline void save(
    Archive & ar,
    const std::unique_ptr< T > &t,
    const unsigned int file_version
) {
    // only the raw pointer has to be saved
    const T * const tx = t.get();
    //ar << tx;
    ar << boost::serialization::make_nvp("px", tx);
}
template<class Archive, class T>
inline void load(
    Archive & ar,
    std::unique_ptr< T > &t,
    const unsigned int file_version
) {
    T *pTarget;
    //ar >> pTarget;
    ar >> boost::serialization::make_nvp("px", pTarget);

#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
    t.release();
    t = std::unique_ptr< T >(pTarget);
#else
    t.reset(pTarget);
#endif
}
template<class Archive, class T>
inline void serialize(
    Archive & ar,
    std::unique_ptr< T > &t,
    const unsigned int file_version
) {
    boost::serialization::split_free(ar, t, file_version);
}
} // namespace serialization
} // namespace boost

class MyDegrees
{
public:
    void setDeg(int d) {
        deg = d;
    }
    int getDeg()const {
        return deg;
    }
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    //{ ar & deg; }
    {
        ar & boost::serialization::make_nvp("DEGS", deg);
    }
    int deg;
};
class gps_position
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    //{ ar & degrees;  }
    {
        ar & boost::serialization::make_nvp("DEGS2", degrees);
        ar & boost::serialization::make_nvp("DEGMAP", deg_map);
    }
    std::unique_ptr<MyDegrees> degrees;
    std::vector<std::unique_ptr<MyDegrees> > deg_map;
public:
    gps_position(): degrees(std::unique_ptr<MyDegrees>(new MyDegrees)) {};
    void setDeg(int d) {
        degrees->setDeg(d);
    }
    int getDeg() const {
        return degrees->getDeg();
    }
};

int TestBasicSerialize(int, char *[])
{
    int numErr = 0;
    double a;
    std::ofstream ofs("filename");
    gps_position g;
    g.setDeg(45);
    std::cout<<g.getDeg()<<std::endl;
    {
        boost::archive::text_oarchive oa(ofs);
        oa << g;
    }
    //{ boost ::archive::xml_oarchive oa(ofs); oa << g;}
    gps_position newg;
    {
        std::ifstream ifs("filename");
        boost::archive::text_iarchive ia(ifs);
        ia >> newg;
        std::cout<<newg.getDeg()<<std::endl;
    }
    return numErr;

}

推荐答案

问题是容器解串器试图复制构造一个unique_ptr. 为了演示,请考虑以下代码,该代码会产生相同的错误:

The problem is that the container deserializer is trying to copy-construct a unique_ptr. To demonstrate, consider the following code which yields the same error:

std::vector< std::unique_ptr<int> > vec;
std::unique_ptr<int> p;
vec.push_back(p); // does not compile!

但是,可以使用std::move解决此问题:

However, this can be solved using std::move:

vec.push_back(std::move(p)); // ok


最省力的解决方案将改为使用可复制构造的智能指针, 例如boost::shared_ptr,它随带 它在boost/serialization/shared_ptr.hpp中的预定义序列化实现.


The least-effort solution would be using a copy constructible smart pointer instead, for example boost::shared_ptr, which comes with its predefined serialization implementation in boost/serialization/shared_ptr.hpp.

下一个解决方案是在您的类中手动序列化向量:

The next solution is to serialize the vector manually inside your class:

//NOTE: this replaces void serialize(...) in gps_position
template<class Archive>
void save(Archive & ar, const unsigned int version) const
{
    ar & BOOST_SERIALIZATION_NVP(degrees);
    size_t size = deg_map.size();
    ar & BOOST_SERIALIZATION_NVP(size);
    for( auto it=deg_map.begin(), end=deg_map.end(); it!=end; ++it )
       ar & boost::serialization::make_nvp("item",*it);
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
    ar & BOOST_SERIALIZATION_NVP(degrees);
    size_t size = 0;
    ar & BOOST_SERIALIZATION_NVP(size);
    deg_map.clear();
    deg_map.reserve(size);
    while( size-- >= 0 ) {
        std::unique_ptr<MyDegrees> p;
        ar & boost::serialization::make_nvp("item",p);
        deg_map.push_back(std::move(p));
    }
}
BOOST_SERIALIZATION_SPLIT_MEMBER()


最后一个解决方案涉及编写自己的容器序列化器, 就像您对unique_ptr所做的一样,它使用std::move添加项目:


The last solution involves writing your own container serializer, like you did for unique_ptr, that uses std::move to add items:

namespace boost { namespace serialization {
//NOTE: do not include boost/serialization/vector.hpp
template<class Archive, class T, class Allocator>
inline void save(
    Archive & ar,
    const std::vector<T, Allocator> &t,
    const unsigned int
){
    collection_size_type count (t.size());
    ar << BOOST_SERIALIZATION_NVP(count);
    for(auto it=t.begin(), end=t.end(); it!=end; ++it)
        ar << boost::serialization::make_nvp("item", (*it));
}

template<class Archive, class T, class Allocator>
inline void load(
    Archive & ar,
    std::vector<T, Allocator> &t,
    const unsigned int
){
    collection_size_type count;
    ar >> BOOST_SERIALIZATION_NVP(count);
    t.clear();
    t.reserve(count);
    while( count-- > 0 ) {
        T i;
        ar >> boost::serialization::make_nvp("item", i);
        t.push_back(std::move(i)); // use std::move
    }
}

template<class Archive, class T, class Allocator>
inline void serialize(
    Archive & ar,
    std::vector<T, Allocator> & t,
    const unsigned int file_version
){
    boost::serialization::split_free(ar, t, file_version);
}
} } // namespace boost::serialization

最后但并非最不重要的是,您应该使用:

And last but not least, you should use:

oa << BOOST_SERIALIZATION_NVP(g);
// and
ia >> BOOST_SERIALIZATION_NVP(newg);

使用XML归档文件时,在您的TestBasicSerialize()中

.

in your TestBasicSerialize() when using the xml archive.

这篇关于提高std的stl集合的序列化unique_ptrs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆