Сериализация нестандартных конструктивных и альтернативных оболочек std::reference
Я попытался сериализовать свою (нейронную) сеть, и в настоящее время я застрял. Кажется, проблема в том, что вы не можете сериализовать std::reference_wrapper
, Я не уверен, стоит ли мне либо изменить способ хранения ссылок на верхние узлы, либо придумать способ их сериализации.
Есть ли альтернативы reference_wrapper
s, которым я пренебрегал и до сих пор избегаю указателей в стиле c? (которых следует избегать, насколько я знаю)
#include <iostream>
#include <fstream>
#include <list>
#include <vector>
#include <functional>
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
typedef float nodeValueType;
typedef std::pair<std::vector<nodeValueType>, std::vector<nodeValueType>> Example;
typedef std::list<Example> ExampleList;
class Node;
class Link
{
public:
Link() = delete;
Link(Node& upperNode, Node& lowerNode)
: Link(upperNode, lowerNode, 1.0e-3f * (std::rand() / (nodeValueType) RAND_MAX))
{
}
Link(Node& upperNode, Node& lowerNode, nodeValueType weight)
: weight_(weight), upperNode_(upperNode), lowerNode_(lowerNode)
{
}
Link(const Link&) = delete;
Link& operator=(const Link&) = delete;
nodeValueType weight_;
std::reference_wrapper<Node> upperNode_;
std::reference_wrapper<Node> lowerNode_;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int version){
ar & this->weight_;
ar & this->upperNode_;
ar & this->lowerNode_;
}
};
class Node
{
public:
Node();
// making it hard to copy us since we really never want to move.
// we are referred in loads of pointers
// therefore moving us invalidates all of them TODO invalidation scheme?
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
void linkTo(Node& other)
{
assert(this->lowerLinks_.max_size() > (this->lowerLinks_.size() + 1) * 2);
// Link creation
this->lowerLinks_.push_back(std::shared_ptr<Link>(new Link(*this, other)));
other.upperLinks_.push_back(std::shared_ptr<Link>(this->lowerLinks_.back()));
}
std::vector<std::shared_ptr<Link>> lowerLinks_;
std::vector<std::shared_ptr<Link>> upperLinks_;
// serialization
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int version){
ar & this->lowerLinks_;
}
};
int main()
{
Node n1;
Node n2;
n2.linkTo(n1);
std::string filename(boost::archive::tmpdir());
filename += "/demofile.txt";
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
oa << n1 << n2;
Node n3,n4;
// open the archive
std::ifstream ifs(filename);
boost::archive::text_iarchive ia(ifs);
// restore the schedule from the archive
ia >> n3 >> n4;
return 0;
}
1 ответ
Есть 2 проблемы, которые нужно преодолеть.
Во-первых, std::reference_wrapper не может иметь значение null, поэтому вы можете рассмотреть тип "ссылка с нулевым значением":
template<class T>
struct NullableReference
{
constexpr NullableReference() : ptr_(nullptr) {}
constexpr NullableReference(T& ref) : ptr_(std::addressof(ref)) {}
constexpr auto operator*() const -> T& { assert(!empty()); return *ptr_; }
constexpr operator T&() const { assert(!empty()); return *ptr_; }
constexpr bool empty() const { return !ptr_; }
template<class Archive>
void serialize(Archive& ar, unsigned int version)
{
ar & ptr_;
}
private:
T* ptr_;
};
Другая причина в том, что Link не имеет конструктора по умолчанию (без сомнения, из-за ненулевых обёрток ссылок).
По этой причине вы можете захотеть рассмотреть пользовательскую обработку конструктора при десериализации Link (это описано в документах Boost IIRC).
Конечно, теперь, когда вы используете NullableReference, вы можете разрешить конструктор по умолчанию для Link:
...
Link() : weight_(), upperNode_(), lowerNode_() {};
nodeValueType weight_;
NullableReference<Node> upperNode_;
NullableReference<Node> lowerNode_;
....