Consider the following example:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/serialization.hpp>
#include <iostream>
#include <sstream>
using namespace boost;
using namespace std;
int main()
{
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
vector<int> src1 = {1}, src2 = {2};
vector<int> dst;
oa << src1;
oa << src2;
string serialized = oss.str();
std::istringstream iss(serialized);
boost::archive::text_iarchive ia(iss);
ia >> dst;
cout << "size=" << dst.size() << endl;
ia >> dst;
cout << "size=" << dst.size() << endl;
}
Output:
size=1
size=1
Everything is fine. However if change vector<int> to vector<string>:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/serialization.hpp>
#include <iostream>
#include <sstream>
using namespace boost;
using namespace std;
int main()
{
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
vector<string> src1 = {"hi"}, src2 = {"hi"};
vector<string> dst;
oa << src1;
oa << src2;
string serialized = oss.str();
std::istringstream iss(serialized);
boost::archive::text_iarchive ia(iss);
ia >> dst;
cout << "size=" << dst.size() << endl;
ia >> dst;
cout << "size=" << dst.size() << endl;
}
Output:
size=1
size=2
Result is appended to dst, not assigned. Why? How "assign semantic" can be achieved?
compiler: gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)
compilation: g++ -std=c++11 test2.cc -lboost_serialization
There is following code at sources of boost 1.58.
if(detail::is_default_constructible<U>()){
t.resize(count);
typename std::vector<U, Allocator>::iterator hint;
hint = t.begin();
while(count-- > 0){
ar >> boost::serialization::make_nvp("item", *hint++);
}
}
else{
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());
}
}
And detail::is_default_constructible
returns false
for std::string
(for some reasons boost::has_trivial_constructor
is used) and true
for int
. So, when U
is int
, resize
will be called and then value assignment will be used, but when U
is std::string
reserve
will be used (reserve don't actually resize container) and then push_back
will be used.
Simple workaround will be just clear
vector before second read from archive.
ia >> dst;
cout << "size=" << dst.size() << endl;
dst.clear();
ia >> dst;
cout << "size=" << dst.size() << endl;