c – boost :: serialization:具有私有默认构造函数的对象在向量中工作,但不在地图中工作
作者:互联网
请考虑以下代码:
#include <boost/serialization/nvp.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
class Foo{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & BOOST_SERIALIZATION_NVP(i);
}
int i;
Foo():i(0){}
public:
Foo(int k):i(k){}
};
int main(int argc, char *argv[])
{
std::vector< Foo> f;
f.push_back(Foo(12));
std::ofstream os("path");
boost::archive::xml_oarchive oa(os);
oa << boost::serialization::make_nvp("f", f);
os.close();
std::vector<Foo> g;
std::ifstream is("path");
boost::archive::xml_iarchive ia(is);
ia >> boost::serialization::make_nvp("f", g);
}
这在序列化Foos矢量时工作正常.但是,如果我尝试序列化Foos的映射,它在私有默认构造函数上失败:
std::map<std::string, Foo> f;
f.insert(std::make_pair("hello", Foo(12)));
std::ofstream os("path");
boost::archive::xml_oarchive oa(os);
oa << boost::serialization::make_nvp("f", f);
os.close();
std::map<std::string, Foo> g;
std::ifstream is("path");
boost::archive::xml_iarchive ia(is);
ia >> boost::serialization::make_nvp("f", g);
失败了
In file included from main.cpp:2:
In file included from /usr/local/include/boost/serialization/nvp.hpp:19:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/utility:70:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_pair.h:109:18: error: field of type 'Foo' has private default constructor
: first(), second() { }
^
/usr/local/include/boost/serialization/access.hpp:132:17: note: in instantiation of member function 'std::pair<const std::basic_string<char>, Foo>::pair' requested here
::new(t)T;
^
/usr/local/include/boost/serialization/serialization.hpp:93:13: note: in instantiation of function template specialization 'boost::serialization::access::construct<std::pair<const std::basic_string<char>, Foo> >' requested here
access::construct(t);
^
/usr/local/include/boost/serialization/serialization.hpp:158:9: note: in instantiation of function template specialization 'boost::serialization::load_construct_data<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >' requested here
load_construct_data(ar, t, v);
^
/usr/local/include/boost/serialization/detail/stack_constructor.hpp:58:31: note: in instantiation of function template specialization 'boost::serialization::load_construct_data_adl<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >' requested here
boost::serialization::load_construct_data_adl(
^
/usr/local/include/boost/serialization/collections_load_imp.hpp:83:48: note: in instantiation of member function 'boost::serialization::detail::stack_construct<boost::archive::xml_iarchive, std::pair<const std::basic_string<char>, Foo> >::stack_construct' requested here
detail::stack_construct<Archive, type> t(ar, v);
^
/usr/local/include/boost/serialization/collections_load_imp.hpp:158:16: note: (skipping 12 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
hint = ifunc(ar, s, item_version, hint);
^
/usr/local/include/boost/archive/detail/common_iarchive.hpp:66:18: note: in instantiation of function template specialization 'boost::archive::load<boost::archive::xml_iarchive, std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
archive::load(* this->This(), t);
^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:86:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
this->detail_common_iarchive::load_override(t.value(), 0);
^
/usr/local/include/boost/archive/xml_iarchive.hpp:93:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > >' requested here
basic_xml_iarchive<Archive>::load_override(t, 0);
^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:60:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > > >' requested here
this->This()->load_override(t, 0);
^
main.cpp:50:8: note: in instantiation of function template specialization 'boost::archive::detail::interface_iarchive<boost::archive::xml_iarchive>::operator>><const boost::serialization::nvp<std::map<std::basic_string<char>, Foo, std::less<std::basic_string<char> >, std::allocator<std::pair<const std::basic_string<char>, Foo> > > > >' requested here
ia >> boost::serialization::make_nvp("f", g);
^
main.cpp:34:5: note: implicitly declared private here
Foo():i(0){}
^
我正在使用clang
Ubuntu clang版本3.4-1ubuntu3(标签/ RELEASE_34 / final)(基于LLVM 3.4)
和Ubuntu 14.04LTS一起提供1.55版本.
我试过提供load_construct_data()函数,如下所示:
namespace boost
{
namespace serialization
{
template<class Archive>
inline void load_construct_data(Archive &archive, Foo*a, unsigned int
file_version)
{
::new(a)Foo(0);
}
}
}
但我仍然得到相同的错误,因为它在实例化std :: pair时需要构造函数
解决方法:
哦.啊哈.
我刚刚使用Boost 1.57.0将情况与map< string,Foo>进行比较.
嗯,你很幸运.您已经找到了另一个库版本依赖项(可能是一个错误).
>不使用它,但提供私有默认构造函数,GCC 4.8.2编译它就好了:Live On Coliru [1]
> GCC 4.9.0虽然无法编译(它也使用了更新版本的标准库). std :: pair<>默认构造函数无法在那里编译,因为Foo不是默认可构造的:Live On Coliru
解
幸运的是,使用save_construct_data / load_construct_data的解决方案再次保存了这一天.
但是,您需要满足这样的事实:元素类型实际上不是Foo,而是std :: pair< T const,Foo>.
template <class Archive, typename K> inline friend void save_construct_data(Archive& ar, std::pair<K, Foo> const* v, const unsigned int) {
std::cerr << __PRETTY_FUNCTION__ << "\n";
ar & boost::serialization::make_nvp("first", v->first);
ar & boost::serialization::make_nvp("second", v->second.i);
}
template <class Archive, typename K> inline friend void load_construct_data(Archive& ar, std::pair<K, Foo>* v, const unsigned int) {
std::cerr << __PRETTY_FUNCTION__ << "\n";
typename std::remove_cv<K>::type first;
ar & boost::serialization::make_nvp("first", first);
int tmp;
ar & boost::serialization::make_nvp("second", tmp);
new(v) std::pair<K, Foo>(first, tmp);
}
现在一切正常:
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <boost/version.hpp>
#include <fstream>
#include <iostream>
class Foo {
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &, const unsigned int) {
std::cerr << __PRETTY_FUNCTION__ << "\n";
}
template <class Archive, typename K> inline friend void save_construct_data(Archive& ar, std::pair<K, Foo> const* v, const unsigned int) {
std::cerr << __PRETTY_FUNCTION__ << "\n";
ar & boost::serialization::make_nvp("first", v->first);
ar & boost::serialization::make_nvp("second", v->second.i);
}
template <class Archive, typename K> inline friend void load_construct_data(Archive& ar, std::pair<K, Foo>* v, const unsigned int) {
std::cerr << __PRETTY_FUNCTION__ << "\n";
typename std::remove_cv<K>::type first;
ar & boost::serialization::make_nvp("first", first);
int tmp;
ar & boost::serialization::make_nvp("second", tmp);
new(v) std::pair<K, Foo>(first, tmp);
}
int i;
public:
Foo(int k) : i(k) {}
friend std::ostream& operator<<(std::ostream& os, Foo const& foo) {
return os << "Foo { " << foo.i << " }";
}
};
namespace boost { namespace serialization {
} }
int main() {
using Data = std::map<std::string, Foo>;
std::cout << "Boost version: " << BOOST_VERSION << "\n";
{
auto f = Data { {"a", 12 }, {"b", 42} };
//for (auto& e : f) std::cout << e.first << ", " << e.second << "\n";
std::ofstream os("path");
boost::archive::xml_oarchive oa(os);
oa << boost::serialization::make_nvp("f", f);
}
{
Data g;
std::ifstream is("path");
boost::archive::xml_iarchive ia(is);
ia >> boost::serialization::make_nvp("f", g);
for (auto& e : g)
std::cout << e.first << ", " << e.second << "\n";
}
}
哪个印刷品:
Boost version: 105700
void save_construct_data(Archive&, const std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_oarchive; K = const std::__cxx11::basic_string<char>]
void Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_oarchive]
void save_construct_data(Archive&, const std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_oarchive; K = const std::__cxx11::basic_string<char>]
void Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_oarchive]
void load_construct_data(Archive&, std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_iarchive; K = const std::__cxx11::basic_string<char>]
void Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_iarchive]
void load_construct_data(Archive&, std::pair<K, Foo>*, unsigned int) [with Archive = boost::archive::xml_iarchive; K = const std::__cxx11::basic_string<char>]
void Foo::serialize(Archive&, unsigned int) [with Archive = boost::archive::xml_iarchive]
a, Foo { 12 }
b, Foo { 42 }
[1](我无法在Coliru上链接它,因为那里的boost库已经重新编译到GCC 5.0 ABI)
笔记
一个更好的,通用的解决方案是对boost :: serialization命名空间中的非默认构造类型一般执行load / save_construct_data技巧.这样,人们就不必“知道”std :: pair<>实施细节.他们可以为自己的用户类型实现load / save_construct_data,JustWork™是将它们放在向量还是映射中.
尽管实现这一点并不简单,但可能会干扰Boost Serialization框架内部的其他一些机制.
我宁愿得到Boost Serialization维护者的一些帮助,以可靠的方式做到这一点.所以,我今天似乎要提交两张票.
标签:c,boost,boost-serialization,stdmap 来源: https://codeday.me/bug/20190727/1558582.html