Opened 7 years ago
Closed 7 years ago
#11342 closed Bugs (fixed)
Vector serialization with non-default-constructible element type fails to compile
Reported by: | Owned by: | Robert Ramey | |
---|---|---|---|
Milestone: | To Be Determined | Component: | serialization |
Version: | Boost 1.58.0 | Severity: | Regression |
Keywords: | Cc: |
Description
The following sample compiles in Boost 1.57.0 but doesn't in Boost 1.58.0:
#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); }
The problem is a new piece of code that tries to switch on is_default_constructible<T>
*at compile time*. That can't work: (from serialization/vector.hpp in the unoptimized version of load(...)):
if(detail::is_default_constructible<U>()){ t.resize(count); // ... snip ... } else{ t.reserve(count); // ... snip ... }
Instead of having the branches in the same flow code, it should be dispatched so that only the applicable branch is instantiated. I tested with this simplistic approach:
namespace sehe_bugfix { template<class Archive, class U, class Allocator> inline void load_elements( Archive & ar, std::vector<U, Allocator> &t, const unsigned int /* file_version */, collection_size_type count, mpl::true_ ){ const boost::archive::library_version_type library_version( ar.get_library_version() ); item_version_type item_version(0); if(boost::archive::library_version_type(3) < library_version){ ar >> BOOST_SERIALIZATION_NVP(item_version); } t.resize(count); typename std::vector<U, Allocator>::iterator hint; hint = t.begin(); while(count-- > 0){ ar >> boost::serialization::make_nvp("item", *hint++); } } template<class Archive, class U, class Allocator> inline void load_elements( Archive & ar, std::vector<U, Allocator> &t, const unsigned int /* file_version */, collection_size_type count, mpl::false_ ){ const boost::archive::library_version_type library_version( ar.get_library_version() ); item_version_type item_version(0); if(boost::archive::library_version_type(3) < library_version){ ar >> BOOST_SERIALIZATION_NVP(item_version); } t.reserve(count); while(count-- > 0){ detail::stack_construct<Archive, U> u(ar, item_version); ar >> boost::serialization::make_nvp("item", u.reference()); t.push_back(u.reference()); ar.reset_object_address(& t.back() , & u.reference()); } } } template<class Archive, class U, class Allocator> inline void load( Archive & ar, std::vector<U, Allocator> &t, const unsigned int file_version, mpl::false_ ){ const boost::archive::library_version_type library_version( ar.get_library_version() ); // retrieve number of elements item_version_type item_version(0); collection_size_type count; ar >> BOOST_SERIALIZATION_NVP(count); sehe_bugfix::load_elements(ar, t, file_version, count, detail::is_default_constructible<U>()); }
Change History (2)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
The fix for this has been checked into the develop and master branch and will appear in the next release. If you can't wait for that, you can clone/download the latest versions from github.
PS. This was in reference to this SO post: http://stackoverflow.com/a/30437359/85371