serialization.h

本文详细解析了FLANN库中的序列化头文件,通过分析关键结构体和类,如bool_、ArchiveBase、InputArchive、OutputArchive等,揭示了序列化和反序列化的实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本人水平有限,又不对之处请见谅。

这是一个序列化的头文件,该文件声明了多个结构体,我会从这几个结构体来逐步分析来解析这个头文件。

源码

-源码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这个头文件才写的这篇博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值