boost::archive_exception causes unhandled exception within VisualStudio2012 - c++

A boost::archive_exception is confounding me. The exception details are as follows
Unhandled exception: boost::archive::archive_exception at memory location...
This occurs when attempting the following boost::serialization load operation that essentially works when BinarySearchTree<std::string> but not when BinarySearchTree<int>
typedef boost::variant<BinarySearchTree<std::string>, BinarySearchTree<int>> BinarySearchTreeVariant;
BinarySearchTreeVariant search_tree_;
BinarySearchTree<std::string> string_search_tree_;
BinarySearchTree<int> int_search_tree_;
boost::shared_ptr<BinarySearchTree<std::string>> binary_string_search_tree_;
boost::shared_ptr<BinarySearchTree<int>> binary_int_search_tree_;
search_tree_ = int_search_tree_;
binary_int_search_tree_.reset(new BinarySearchTree<int>());
try{
if(!binary_int_search_tree_->load(binary_int_search_tree_, search_tree_name))
throw CustomException("Load of binary search tree to disk fail");
}
catch(CustomException &custom_exception){ }
The code that defines load is as follows
bool load(boost::shared_ptr<BinarySearchTree> &tree, const std::string &search_tree_file_name)
{
// create and open an archive for output
std::ifstream reader(search_tree_file_name);
if(reader){
boost::archive::text_iarchive serial_reader(reader);
// read class state from archive
serial_reader >> *tree; <<<--- Unhandled Exception
// archive and stream closed when destructors are called
}else if(reader.fail()){
reader.clear();
}
return true;
}
My search tree is defined with boost::serialization as follows
class BinarySearchTree{
private:
class BinarySearchTreeNode{
public:
friend class BinarySearchTree;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &archive, const unsigned int /* file_version */){
archive & key;
archive & index;
archive & left;
archive & right;
}
T key;
long index;
boost::shared_ptr<BinarySearchTreeNode> left;
boost::shared_ptr<BinarySearchTreeNode> right;
}; // End Tree Node Class Definition
boost::shared_ptr<BinarySearchTreeNode> root;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &archive, const unsigned int version){
archive & root;
}
};

Related

Able to serialize with boost but unable to deserialize std::shared_ptr

boost serialization
namespace boost {
namespace serialization {
template <class Archive, class T>
inline void save
(Archive &archive,
const std::shared_ptr<T> subtree,
const unsigned int file_version)
{
// only the raw pointer has to be saved
const T *const subtree_x = subtree.get();
archive << subtree_x;
}
template <class Archive, class T>
inline void load
(Archive &archive,
std::shared_ptr<T> subtree,
const unsigned int file_version)
{
T *p_subtree;
archive >> p_subtree;
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
subtree.release();
subtree = std::shared_ptr< T >(p_subtree);
#else
subtree.reset(p_subtree);
#endif
}
template <class Archive, class T>
inline void serialize
(Archive &archive,
std::shared_ptr<T> subtree, // no const or else get compile-time error
const unsigned int file_version)
{
boost::serialization::split_free(archive, subtree, file_version);
}
} // namespace serialization
} // namespace boost
tree class
class Tree{
private:
class TreeNode{
public:
std::shared_ptr<TreeNode> node_factory(const T &new_key, const long &new_index)
{
return std::shared_ptr<TreeNode>(new TreeNode(new_key, new_index));
}
friend class Tree;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &archive, const unsigned int /* file_version */){
archive & key;
archive & index;
archive & left;
archive & right;
}
T key;
long index;
std::shared_ptr<TreeNode> left;
std::shared_ptr<TreeNode> right;
}; // End Tree Node Class Definition
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &archive, const unsigned int version){
archive & root;
}
};
writer
bool save(std::shared_ptr<Tree> &tree, const std::string &search_tree_file_name)
{
// create and open a binary archive for output
std::ofstream writer(search_tree_file_name, std::ofstream::out | std::ofstream::binary);
if(writer){
boost::archive::binary_oarchive serial_writer(writer);
//set_flags(0, true);
// write class instance to archive
serial_writer << *tree;
// archive and stream closed when destructors are called
}else if(writer.fail()){
writer.clear();
}
return true;
}
reader
enter code here bool load(std::shared_ptr<Tree> &tree, const std::string &search_tree_file_name)
{
// create and open a binary archive for output
std::ifstream reader(search_tree_file_name, std::ifstream::in | std::ifstream::binary);
if(reader){
boost::archive::binary_iarchive serial_reader(reader);
// read class state from archive
serial_reader >> *tree;
// archive and stream closed when destructors are called
}else if(reader.fail()){
reader.clear();
}
return true;
}
I have written to and verified the successful serialization to a file but fail to deserialize from and into a usable object.
Whether I am writing in text or binary, I can verify the serialized output is correct but, for some reason, the serialize output does not deserialize and I am left with an empty object when loading.
Have a look at these links, might provide you some clue.
http://www.boost.org/doc/libs/1_49_0/libs/serialization/doc/shared_ptr.html
& http://www.boost.org/doc/libs/1_49_0/libs/serialization/doc/shared_ptr2.html
Although #Arun provided great documentation references useful for utilizing std::shared_ptr, I instead chose to employ boost::shared_ptr with boost::serialization and it has cured my de-serialization problem.

serialize is not a member of std::unique_ptr

Is this question more appropriate for Boost forums? The complete code is referenced below and I do not consider that I have incorrectly attempted to convert an auto_ptr serialization example into a unique_ptr example as compared to other unique_ptr examples on this site. Thus, why would I receive a compilation error deep within a Boost library? I have used Boost serialization on standard containers before with no problems and, although this is a custom adapter, if similar examples have compiled, why not this?
I referenced http://www.boost.org/doc/libs/1_51_0/libs/serialization/example/demo_auto_ptr.cpp in an attempt to serialize my binary tree using a custom adaptor. Below is a code dump representing an sscce.
// disables conversion from 'std::streamsize' to 'size_t', possible loss of data
#pragma warning(disable:4244)
#ifndef BINARY_SEARCH_TREE_H_
#define BINARY_SEARCH_TREE_H_
#include<functional>
#include<memory>
#include<fstream>
#include<boost/archive/binary_oarchive.hpp>
#include<boost/archive/binary_iarchive.hpp>
#define BST_FILE_NAME "tree.dat" // default filename used to save and load
namespace boost {
namespace serialization {
template <class Archive, class T>
inline void save
(Archive &archive,
const std::unique_ptr<T> &subtree,
const unsigned int file_version)
{
// only the raw pointer has to be saved
const T *const subtree_x = subtree.get();
archive << subtree_x;
}
template <class Archive, class T>
inline void load
(Archive &archive,
const std::unique_ptr<T> &subtree,
const unsigned int file_version)
{
T *p_subtree;
archive >> p_subtree;
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
subtree.release();
subtree = std::unique_ptr< T >(p_subtree);
#else
subtree.reset(p_subtree);
#endif
}
template <class Archive, class T>
inline void serialize
(Archive &archive,
const std::unique_ptr<T> &subtree,
const unsigned int file_version)
{
boost::serialization::split_free(archive, subtree, file_version);
}
} // namespace serialization
} // namespace boost
template <class T = int>
class BinarySearchTree{
class BinarySearchTreeNode{
public:
std::unique_ptr<BinarySearchTreeNode> node_factory(const T &new_key, const T &new_index){
return std::unique_ptr<BinarySearchTreeNode>(new BinarySearchTreeNode(new_key, new_index)); }
BinarySearchTreeNode(BinarySearchTreeNode &&other) : key(other.key), index(other.index), left(std::move(other.left)),
right(std::move(other.right)) {key = index = left = right = nullptr; }
BinarySearchTreeNode &operator=(BinarySearchTreeNode &&rhs) { if(this != rhs) { key = rhs.key; index = rhs.index;
left = std::move(rhs.left); right = std::move(rhs.right);
rhs.key = rhs.index = rhs.left = rhs.right = nullptr;} return *this;}
~BinarySearchTreeNode() {} // Note to self; don't hide the destructor
friend class BinarySearchTree;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &archive, const unsigned int /* file_version */){
archive & key;
archive & index;
archive & left;
archive & right;
}
T key;
long index;
std::unique_ptr<BinarySearchTreeNode> left;
std::unique_ptr<BinarySearchTreeNode> right;
BinarySearchTreeNode() {}
BinarySearchTreeNode(const T &new_key, const T &new_index) :key(new_key), index(new_index),
left(nullptr), right(nullptr) {}
};
std::unique_ptr<BinarySearchTreeNode> root;
std::list<T> tree_keys;
std::list<long> tree_indicies;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &archive, const unsigned int version){
archive & root;
}
BinarySearchTree(const BinarySearchTree &other){}
BinarySearchTree &operator=(const BinarySearchTree &rhs){}
std::unique_ptr<BinarySearchTreeNode> insert(const T &new_key, const T &new_index,
std::unique_ptr<BinarySearchTreeNode> &tree){
if(tree == nullptr){
return root->node_factory(new_key, new_index);
}else if(std::less<T> () (new_key, tree->key)){ // Left insertion
tree->left = insert(new_key, new_index, tree->left);
return std::move(tree);
}else { // Right insertion
tree->right = insert(new_key, new_index, tree->right);
return std::move(tree);
}
}
public:
BinarySearchTree() : root(nullptr) {}
BinarySearchTree(BinarySearchTree &&other) : root(std::move(other.root)) { other.root = nullptr; }
BinarySearchTree &operator=(BinarySearchTree &&rhs) { if(this != rhs) { root = std::move(rhs.root);
rhs.root = nullptr} return *this; }
bool insert_into_tree(const T &new_key, const T &new_index){
if(new_key == NULL){
return false;
}
root = std::move(insert(new_key, new_index, root));
return true;
}
void save(const BinarySearchTree &tree)
{
// create and open a binary archive for output
std::ofstream writer(BST_FILE_NAME, std::ofstream::out | std::ofstream::binary);
if(writer){
boost::archive::binary_oarchive serial_writer(writer);
//set_flags(0, true);
// write class instance to archive
serial_writer << tree;
// archive and stream closed when destructors are called
}else if(writer.fail()){
writer.clear();
}
}
void load(BinarySearchTree &tree)
{
// create and open a binary archive for output
std::ifstream reader(BST_FILE_NAME, std::ifstream::in | std::ifstream::binary);
if(reader){
boost::archive::binary_iarchive serial_reader(reader);
// read class state from archive
serial_reader >> tree;
// archive and stream closed when destructors are called
}else if(reader.fail()){
reader.clear();
}
}
~BinarySearchTree() {}
};
#endif
The code above compiles as does any usage of the tree member functions. Once choosing to call save, that is when the compiler error appears. Here is main:
#include<cstdlib>
#include "physical_view.h"
using namespace std;
int main(int argc, char *argv[]){
BinarySearchTree<> tree;
tree.insert_into_tree(10, 5);
tree.insert_into_tree(5, 15);
tree.insert_into_tree(15, 10); <--------- All is wonderful to here!
tree.save(tree); <---------- Compiler unhappy here!
return EXIT_SUCCESS;
}
How about that compiler error:
Error 1 error C2039: 'serialize' : is not a member of 'std::unique_ptr<_Ty>' c:\boost_12\include\boost-1_53_1\boost\serialization\access.hpp 118
I thank you for helping me resolve this compiler error.
The is that the signature of your serialize and load functions is incorrect. The std::unique_ptr<T> argument needs to be non-const for both of them. Since it can't deduce the types (due to the const), it simply ignores the overload and fails to find it at all.

Boost.Serialization: Error on Calling Class Method during serialization process

I have the following problem when I try to call method in "TestSerialize" class during serialization process.
Here is my code:
class TestSerialize
{
public:
std::string GetVal() { return Val + "abc"; }
void SetVal(std::string tVal) { Val = tVal.substr(0, 2); }
protected:
std::string Val;
friend class boost::serialization::access;
template<class Archive> void save(Archive & ar, const unsigned int version) const
{
using boost::serialization::make_nvp;
std::string tVal = GetVal(); // Error here
ar & make_nvp("SC", tVal);
}
template<class Archive> void load(Archive & ar, const unsigned int version)
{
using boost::serialization::make_nvp;
std::string tVal;
ar & make_nvp("SC", tVal);
SetVal(tVal);
}
BOOST_SERIALIZATION_SPLIT_MEMBER();
};
int main()
{
TestSerialize tS;
std::ofstream ofs("test.xml");
boost::archive::xml_oarchive oa(ofs, boost::archive::no_header);
oa << BOOST_SERIALIZATION_NVP(tS);
ofs.close();
return 0;
}
The error that I encountered is:
'TestSerialize::GetVal' : cannot convert 'this' pointer from 'const TestSerialize' to 'TestSerialize &'
This error only happens on "save" but not "load"
I wonder why I get this error. I would like to know what Boost.Serialization do such that we have these two different behaviors.
I use Boost Library 1.47.0
save is a const function and can only call other const functions. GetVal isn't. Change it:
std::string GetVal() const { ... }

Deserialize object with references and no default constructor (boost::serialization)

Is it possible in boost::serialization library to deserialize (polymorphic) objects with references and no default constructor?
class Example
{
int& value;
public:
Example(int _value): value(_value) {}
virtual ~Example() {}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
ar & value;
}
};
class Usage
{
Example* example;
public:
Usage(): example(new Example(123)) {}
~Usage() { delete example; }
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
ar & example;
}
};
...
// serialize and deserialize object with reference and no default constructor
{
Usage source;
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa & source;
Usage target;
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
ia & target; // does not compile
}
As for non-default constructible object, I'd recommend to look the item
Non-Default Constructors
here.
Your class can be serialized by
writing your own function template load_construct_data and save_construct_data.

Serialization tree structure using boost::serialization

I have to serialize libkdtree++ in my program, the tree structures are briefly described as following:
struct _Node_base {
_Node_base * _M_parent, *_M_left, * _M_right;
template<Archive>
serialize(Archive &ar, const unsigned int version) {
ar & _M_left & _M_right;
}
}
template<typename V>
struct _Node : public _Node_base {
typedef V value_type;
value_type value;
template<Archive>
serialize(Archive &ar, const unsigned int version) {
ar.register_type(static_cast<_Node*>(NULL));
ar & boost::serialization::base_object<_Node_base>(*this);
ar & value;
}
}
struct Tree {
_Node * root;
template<Archive>
serialize(Archive &ar, const unsigned int version) {
ar & root;
}
}
This program reports "stream error".
But from the "serailzed file", it lacks the value fields for the children nodes of roots. Thus I think it is possible that BaseNode serialized _M_left and _M_right pointer. However since _Node_base have no idea about the value type of _Node, so it looks hard to add "ar.register_type" to _Node_base.serialize().
The pointer_conflict exception documentation states (sic):
pointer_conflict, // an attempt has been made to directly
// serialization::detail an object
// after having already serialzed the same
// object through a pointer. Were this permited,
// it the archive load would result in the
// creation of an extra copy of the obect.
I think the conflict occurs where each is serialised by a ptr in BaseNode::serialize and via the direct object, the *Node expression, in Node::serialize. However since the base_object function takes a reference and not a ptr I'm not sure how you would avoid this.
One possibility is to not serialize the parent ptr. Instead, after deserialization, do a walk of the tree and fix up the parent ptrs to point to the node parent. E.g. add the following method to BaseNode :
void fix (BaseNode* parent = 0)
{
this->parent = parent;
if (left != 0)
left->fix (this);
if (right != 0)
right->fix (this);
}
Then just call root->fix ()
The following solution for libkdtree++ & boost::serialization seems work:
// KDTree::_Node
friend class boost::serialization::access;
template<class Archive>
//void serialize(Archive & ar, const unsigned int version)
void save(Archive & ar, const unsigned int version) const
{
ar.register_type(static_cast< _Link_type>(NULL));
ar & boost::serialization::base_object<_Node_base>(*this);
_Link_type left = static_cast<_Link_type>(_M_left);
_Link_type right = static_cast<_Link_type>(_M_right);
ar & left & right;
ar & _M_value;
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
ar.register_type(static_cast< _Link_type>(NULL));
ar & boost::serialization::base_object<_Node_base>(*this);
_Link_type left, right;
ar & left & right;
ar & _M_value;
if (left) {
left->_M_parent = this;
}
if (right) {
right->_M_parent = this;
}
_M_left = left;
_M_right = right;
}
BOOST_SERIALIZATION_SPLIT_MEMBER()