本人水平有限,又不对之处请见谅。
这是一个序列化的头文件,该文件声明了多个结构体,我会从这几个结构体来逐步分析来解析这个头文件。
-源码246——250行 结构体 bool_
template <bool C_>
struct bool_ {
static const bool value = C_;
typedef bool value_type;
};
用模版的方式定义了一个结构体。
bool_<true> a;
a.value的值为true。
bool_<false> b;
b.value的值为false。
-源码253——255行 ArchiveBase
class ArchiveBase
{
public:
void* getObject() { return object_; }
void setObject(void* object) { object_ = object; }
private:
void* object_;
};
这是flann库的文档基类,主要用于对对象进行序列化,大家将到后面看到其如何使用。
其中 void* object_; 是指向文件的指针。
-源码266——281 InputArchiive
template<typename Archive>
class InputArchive : public ArchiveBase
{
protected:
InputArchive() {};
public:
typedef bool_<true> is_loading;
typedef bool_<false> is_saving;
template<typename T>
Archive& operator& (T& val)
{
Serializer<T>::load(*static_cast<Archive*>(this),val);
return *static_cast<Archive*>(this);
}
};
该类继承于ArchiveBase,如其名字InputArchive,它的主要作用是加载对象,对于一个输入的文档,所以is_loading值为true,is_saving值为false,该类重载了一个操作符&。该类也是一个基类,并不适合实例化。
-源码284——299 OutputArchive
template<typename Archive>
class OutputArchive : public ArchiveBase
{
protected:
OutputArchive() {};
public:
typedef bool_<false> is_loading;
typedef bool_<true> is_saving;
template<typename T>
Archive& operator& (const T& val)
{
Serializer<T>::save(*static_cast<Archive*>(this),val);
return *static_cast<Archive*>(this);
}
};
OutputArchive继承于ArchiveBase,不同于InputArchive的是。该类是用于save的,所以is_loading.value为false,is_saving.value值为true.用法同InputArchive。
注:这两个类都直接用,一般都作为基类。
-源码303——334 SizeArchive
class SizeArchive : public OutputArchive<SizeArchive>
{
size_t size_;
public:
SizeArchive() : size_(0)
{
}
template<typename T>
void save(const T& val)
{
size_ += sizeof(val);
}
template<typename T>
void save_binary(T* ptr, size_t size)
{
size_ += size;
}
void reset()
{
size_ = 0;
}
size_t size()
{
return size_;
}
};
我暂且称其类为尺寸文档。它比OutputArchive多了一个存储size的功能,并针对size提供了一些操作。
-源码355——396
class SaveArchive : public OutputArchive<SaveArchive>
{
FILE* stream_;
bool own_stream_;
public:
SaveArchive(const char* filename)
{
stream_ = fopen(filename, "w");
own_stream_ = true;
}
SaveArchive(FILE* stream) : stream_(stream), own_stream_(false)
{
}
~SaveArchive()
{
if (own_stream_) {
fclose(stream_);
}
}
template<typename T>
void save(const T& val)
{
fwrite(&val, sizeof(val), 1, stream_);
}
template<typename T>
void save(T* const& val)
{
// don't save pointers
//fwrite(&val, sizeof(val), 1, handle_);
}
template<typename T>
void save_binary(T* ptr, size_t size)
{
fwrite(ptr, size, 1, stream_);
}
};
该类SaveArchive继承与OutputArchive,它提供并实现了对对象save的接口。
成员变量:FILE * stream; 指向存储的文件
bool own_stream_;指明该文件指针是否独享
方法: save(const T& val);
将值存储到指定文件中
save_binary(T *ptr, size_t size);
存储一个数据块,首地址为ptr,大小为size个字节。
class LoadArchive : public InputArchive<LoadArchive>
{
FILE* stream_;
bool own_stream_;
public:
LoadArchive(const char* filename)
{
stream_ = fopen(filename, "r");
own_stream_ = true;
}
LoadArchive(FILE* stream) : stream_(stream), own_stream_(false)
{
}
~LoadArchive()
{
if (own_stream_) {
fclose(stream_);
}
}
template<typename T>
void load(T& val)
{
size_t ret = fread(&val, sizeof(val), 1, stream_);
if (ret!=1) {
throw FLANNException("Error loading from file");
}
}
template<typename T>
void load(T*& val)
{
// don't load pointers
//fread(&val, sizeof(val), 1, handle_);
}
template<typename T>
void load_binary(T* ptr, size_t size)
{
size_t ret = fread(ptr, size, 1, stream_);
if (ret!=1) {
throw FLANNException("Error loading from file");
}
}
};
原理同SaveArchive不过LoadArchive执行的是加载操作。
回过头来,我们来看一看它是如何进行序列化操作的。
大家注意到,InputArchive,OutputArchive都重载了操作符&,所以我们可称为&为序列化操作符,它们执行时分别调用了Serializer中的静态成员函数load与save,下面我们来仔细看看这Serializer结构体,如何实现这两个函数。
作者是用模版的方式实现了Serializer
大家阅读源码前一部分会发现,除了对vector,Map这两个类型的Serializer,其他类型的Serializer直接调用了Archive类中的相关函数,所以大家理解之前Archive中的相关函数,就能很好的理解。
而对应vector,Map这两种类型需要对其每个元素进行序列化,所以才与原先的有所不同,我认为仔细读代码的人都能很清楚了理解Serilizer的句法,我这就不多赘述了,我是为了帮同我一样的新手来更容易理解serialization.h这个头文件才写的这篇博客。