Hello list,
I'm using Visual C++ Express 2008 and Boost 1.42. I have a graph of
classes I'm trying to serialise, and I'm using shared_ptrs to manage
multiple references to the same object, but I can't deserialise my
graph corectly. I get errors like:
First-chance exception at 0x7c812afb in sams-6.exe: Microsoft C++
exception: std::basic_string
at memory location 0x03d7f28c..
HEAP[sams-6.exe]: Invalid allocation size - AC1051B4 (exceeded 7ffdefff)
First-chance exception at 0x7c812afb in sams-6.exe: Microsoft C++
exception: std::bad_alloc at memory location 0x03c7dc5c..
HEAP[sams-6.exe]: Invalid allocation size - AC1051A8 (exceeded 7ffdefff)
Here are my classes:
struct stats_t {
friend class boost::serialization::access;
typedef int ts_t;
size_t bytes, packets;
ts_t firstPacketTs, lastPacketTs;
stats_t() : bytes(0), packets(0), firstPacketTs(0), lastPacketTs(0) { }
private:
template<class Archive> void serialize(Archive &ar, unsigned int
/* file_version */) {
ar & bytes & packets & firstPacketTs & lastPacketTs;
}
};
struct dest_port_t {
friend class boost::serialization::access;
endpoint_t endpoint;
shp_socket_t socket;
bool inUse;
stats_t stats;
std::string name;
boost::asio::ip::udp::endpoint baue;
dest_port_t(const endpoint_t &e, const std::string
&n=std::string()) : endpoint(e), inUse(false), name(n),
baue(boost::asio::ip::address_v4(e.first), e.second) { }
private:
template<class Archive> void serialize(Archive &ar, unsigned int
/* file_version */) {
ar & endpoint & name & inUse & stats;
}
};
typedef boost::shared_ptr shp_dest_port_t;
typedef std::set dest_port_shpset_t;
BOOST_SERIALIZATION_SHARED_PTR( dest_port_t )
namespace boost { namespace serialization {
template<class Archive> inline void load_construct_data(Archive
&ar, dest_port_t *dpp, unsigned int /* file_version */) {
endpoint_t endpoint;
std::string name;
ar >> endpoint;
ar >> name;
::new(dpp) dest_port_t(endpoint, name);
ar >> dpp->inUse;
ar >> dpp->stats;
}
} }
struct dest_t {
friend class boost::serialization::access;
endpoint_t endpoint;
dest_port_shpset_t ports;
size_t connections;
std::string name;
dest_t(const endpoint_t &e=endpoint_t(), const std::string
&n=std::string()) : endpoint(e), connections(0), name(n) { }
private:
template<class Archive> void serialize(Archive &ar, unsigned int
/* file_version */) {
ar & endpoint & ports & connections & name;
}
};
typedef boost::shared_ptr shp_dest_t;
typedef std::set dest_shpset_t;
BOOST_SERIALIZATION_SHARED_PTR( dest_t )
struct source_t {
friend class boost::serialization::access;
endpoint_t endpoint;
size_t connections;
stats_t stats;
const bool foreign; // True for 'unrecognised' sources.
std::string name;
source_t(const endpoint_t &e=endpoint_t(), bool f=false, const
std::string &n=std::string()) : endpoint(e), connections(0),
foreign(f), name(n) { }
private:
template<class Archive> void serialize(Archive &ar, unsigned int
/* file_version */) {
ar & endpoint & connections & stats & const_cast(foreign) & name;
}
};
typedef boost::shared_ptr shp_source_t;
typedef std::set source_shpset_t;
BOOST_SERIALIZATION_SHARED_PTR( source_t )
struct connection_t {
friend class boost::serialization::access;
shp_source_t source;
shp_dest_port_t dest_port;
shp_dest_t dest;
stats_t stats;
connection_t(const shp_source_t &s, const shp_dest_port_t &dp,
const shp_dest_t &d=shp_dest_t())
: source(s), dest_port(dp), dest(d) { }
private:
template<class Archive> void serialize(Archive &ar, unsigned int
/* file_version */) {
ar & source & dest_port & dest & stats;
}
};
typedef std::set connection_set_t;
typedef std::map talkspurt_map_t;
namespace boost { namespace serialization {
template<class Archive> inline void load_construct_data(Archive
&ar, connection_t *cp, unsigned int /* file_version */) {
shp_source_t src;
shp_dest_port_t dest_port;
shp_dest_t dest;
ar >> src;
ar >> dest_port;
ar >> dest;
::new(cp) connection_t(src, dest_port, dest);
ar >> cp->stats;
}
} }
class UdpWorker : public syn::Thread {
protected:
size_t errors_;
stats_t total_, invalid_, ignored_;
dest_shpset_t dests_;
source_shpset_t sources_;
talkspurt_map_t talkspurtMap_;
};
So it's UdpWorker -> dest_shpset_t -> dest_t -> dest_port_shpset_t -> stats_t,
UdpWorker -> source_shpset_t -> source_t -> stats_t,
UdpWorker -> talkspurt_map_t -> connection_set_t -> shp_source_t etc.
The code to save is:
void UdpWorker::save() {
try {
ofstream os(stateFile_.c_str());
boost::archive::text_oarchive oa(os);
oa << errors_;
oa << total_;
oa << invalid_;
oa << ignored_;
oa << sources_;
oa << dests_;
oa << talkspurtMap_;
}
catch (boost::archive::archive_exception &ae) {
log("UdpWorker::save(): Error - caught archive_exception
\"%s\" while saving to text archive \"%s\".",
ae.what(), stateFile_.c_str());
}
catch (...) {
log("UdpWorker::save(): Error - caught unknown exception while
saving to text archive \"%s\".", stateFile_.c_str());
}
}
And the loading code is very similar:
void UdpWorker::load() {
try {
ifstream is(stateFile_.c_str());
boost::archive::text_iarchive ia(is);
ia >> errors_;
ia >> total_;
ia >> invalid_;
ia >> ignored_;
ia >> sources_;
ia >> dests_;
ia >> talkspurtMap_;
}
catch (boost::archive::archive_exception &ae) {
log("UdpWorker::load(): Error - caught archive_exception
\"%s\" while loading from text archive \"%s\".",
ae.what(), stateFile_.c_str());
}
catch (...) {
log("UdpWorker::load(): Error - caught unknown exception while
loading from text archive \"%s\".", stateFile_.c_str());
}
}
The archive seems to be written OK, but when loading it seems to load
the sources_ set OK and then die on the dests_ set, with the bad_alloc
exceptions given above. So the talkspurt_map_t hasn't been tested
yet...
I've tried the binary archive, but I get pretty much the same error.
I'd really appreciate it if someone with a more experienced eye could
have a look at my classes and tell me if there's anything suspicious.
Is BOOST_SERIALIZATION_SHARED_PTR still required in 1.42? I couldn't
find any mention of it in the documentation, but many examples seem to
use it. It looks like it's a no-op anyway on this compiler.
Thanks very much,
John :^P
--
John Pallister
john@johnp.net
john@synchromesh.com