Template serialization - shared_ptr<class T>

news2024/11/27 15:39:16

下面包含的所有代码片段都在 boost::serialization 命名空间内定义。
shared_ptr < T > 在 shared_ptr.hpp 中定义。

shared_ptr 的一般类轮廓如下:

  • shared_ptr 包括以下成员:
    • T *px;
    • shared_count pn;,其中包含指向:
      • sp_counted_base_impl<T, …>,它派生自多态抽象类sp_counted_base

序列化过程沿着上述树结构进行。

首次尝试实现 shared_ptr 的序列化只是序列化 shared_ptr 的相关成员。这几乎是微不足道的操作:

template<class Archive, class T>
inline void serialize(
    Archive & ar,
    shared_ptr<T> & t,
    const unsigned int file_version,
    int
){
    ar & t.px; // save the raw pointer
    ar & t.pn; // save the shared reference count
}

So far so good. Now for the serialization of shared_count:

template<class Archive>
inline void save(
    Archive & ar,
    const boost::detail::shared_count & t,
    const unsigned int file_version
){
    ar << t.pi_;
}

template<class Archive>
inline void load(
    Archive & ar,
    boost::detail::shared_count & t,
    const unsigned int file_version
){
    ar >> t.pi_;
}

这个库的一个重要特点是可以在不更改类或模板的声明或定义的情况下指定类或模板的序列化方式。这被称为非侵入式序列化。

shared count 中的 pi_member 是指向 sp_counted_base_impl 实例的指针。由于这个类没有默认构造函数,因此序列化需要指定以下重载函数:

template<class Archive, class P, class D>
inline void save_construct_data(
    Archive & ar,
    const boost::detail::sp_counted_base_impl * t, 
    const unsigned int file_version
){
    // variables used for construction
    ar << t->ptr;
    ar << *t;
}

template
inline void load_construct_data(
    Archive & ar,
    boost::detail::sp_counted_base_impl * t, 
    const unsigned int file_version
){
    P ptr_;
    ar >> ptr_;
    // placement new
    ::new(t)boost::detail::sp_counted_base_impl(ptr_,  D());
    ar >>; *t;
}

这个语句 ar >> ptr_ 很关键。它用于反序列化之前序列化的相同指针。默认的对象跟踪机制会确保不会创建多于一个对象的实例,同时多次反序列化返回的指针都指向相同的对象。因此,无论创建了多少个与特定对象相对应的 shared_ptr 或 shared_count 实例,它们都将指向同一个对象。

由于 sp_counted_base_impl<P, D> 是从 sp_counted_base 派生出来的,因此需要以下操作:

template<class Archive, class P, class D>
inline void serialize(
    Archive & ar,
    boost::detail::sp_counted_base_impl<P, D> & t,
    const unsigned int file_version,
    int
){
    ar & boost::serialization::base_object<
	boost::detail::sp_counted_base
    >(*this);
}

这将反过来需要对其基类进行序列化:

inline void serialize(
    Archive & ar,
    boost::detail::sp_counted & t,
    const unsigned int file_version,
    int
){
}

demo_shared_ptr.cpp

#include <iomanip>
#include <iostream>
#include <cstddef> // NULL
#include <fstream>
#include <string>

#include <cstdio> // remove
#include <boost/config.hpp>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{ 
    using ::remove;
}
#endif

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/tmpdir.hpp>

#include <boost/serialization/shared_ptr.hpp>

///
// test shared_ptr serialization
class A
{
private:
    friend class boost::serialization::access;
    int x;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int /* file_version */){
        ar & x;
    }
public:
    static int count;
    A(){++count;}    // default constructor
    virtual ~A(){--count;}   // default destructor
};

BOOST_SERIALIZATION_SHARED_PTR(A)

/
// ADDITION BY DT
class B : public A
{
private:
    friend class boost::serialization::access;
    int x;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int /* file_version */){
        ar & boost::serialization::base_object<A>(*this);
    }
public:
    static int count;
    B() : A() {};
    virtual ~B() {};
};

BOOST_SERIALIZATION_SHARED_PTR(B)

/

int A::count = 0;

void display(boost::shared_ptr<A> &spa, boost::shared_ptr<A> &spa1)
{
    std::cout << "a = 0x" << std::hex << spa.get() << " ";
    if (spa.get()) std::cout << "is a " << typeid(*(spa.get())).name() << "* ";
    std::cout << "use count = " << std::dec << spa.use_count() << std::endl;
    std::cout << "a1 = 0x" << std::hex << spa1.get() << " ";
    if (spa1.get()) std::cout << "is a " << typeid(*(spa1.get())).name() << "* ";
    std::cout << "use count = " << std::dec << spa1.use_count() << std::endl;
    std::cout << "unique element count = " << A::count << std::endl;
}

int main(int /* argc */, char * /*argv*/[])
{
    std::string filename(boost::archive::tmpdir());
    filename += "/testfile";

    // create  a new shared pointer to ta new object of type A
    boost::shared_ptr<A> spa(new A);
    boost::shared_ptr<A> spa1;
    spa1 = spa;
    display(spa, spa1);
    // serialize it
    {
        std::ofstream ofs(filename.c_str());
        boost::archive::text_oarchive oa(ofs);
        oa << spa;
        oa << spa1;
    }
    // reset the shared pointer to NULL
    // thereby destroying the object of type A
    spa.reset();
    spa1.reset();
    display(spa, spa1);
    // restore state to one equivalent to the original
    // creating a new type A object
    {
        // open the archive
        std::ifstream ifs(filename.c_str());
        boost::archive::text_iarchive ia(ifs);

        // restore the schedule from the archive
        ia >> spa;
        ia >> spa1;
    }
    display(spa, spa1);
    spa.reset();
    spa1.reset();

    std::cout << std::endl;
    std::cout << std::endl;
    std::cout << "New tests" << std::endl;

    /
    // ADDITION BY DT
    // create  a new shared pointer to ta new object of type A
    spa = boost::shared_ptr<A>(new B);
    spa1 = spa;
    display(spa, spa1);
    // serialize it
    {
        std::ofstream ofs(filename.c_str());
        boost::archive::text_oarchive oa(ofs);
        oa.register_type(static_cast<B *>(NULL));
        oa << spa;
        oa << spa1;
    }
    // reset the shared pointer to NULL
    // thereby destroying the object of type B
    spa.reset();
    spa1.reset();
    display(spa, spa1);
    // restore state to one equivalent to the original
    // creating a new type B object
    {
        // open the archive
        std::ifstream ifs(filename.c_str());
        boost::archive::text_iarchive ia(ifs);

        // restore the schedule from the archive
        ia.register_type(static_cast<B *>(NULL));
        ia >> spa;
        ia >> spa1;
    }
    display(spa, spa1);
    ///
    std::remove(filename.c_str());

    // obj of type A gets destroyed
    // as smart_ptr goes out of scope
    return 0;
}

结果

在这里插入图片描述

这表示我们还没有完成。由于默认的对象跟踪,无论有多少 shared 指针指向相同的对象,sp_counted_base_impl<P, D> 只会被创建一次。当然,必须这样做。引用计数从1开始,并且永远不会递增。必须在序列化函数中添加代码来维护正确的引用计数。
对空基类 sp_counted_base 的序列化过程似乎是额外的开销。查看 base_object.hpp 中的代码,可以发现 base_object.hpp 提供了两个功能:

  • 调用基类数据的序列化。
  • 作为副作用,“注册”了基类/派生类关系,以便在运行时可以在基类和派生类之间进行指针转换。

在这种情况下,我们只需要后者的功能,因此我们可以用以下方式替换基对象的序列化操作:

// register the relationship between each derived class
// its polymorphic base
void_cast_register<
    boost::detail::sp_counted_base_impl<P, D>
    boost::detail::sp_counted_base, 
>();

并且我们不必为 sp_counted_base 包含一个无关紧要的序列化器。

最后,如果我们希望能够在 XML 存档中使用这种序列化方式,我们需要指定名称-值对包装器。

实际上,即使这只是一个开始。在这个实现中没有解决的问题包括:

  • weak_ptr 没有被处理。我甚至还没有研究过这个问题。
  • 其他可能与 shared_ptr 交互的智能指针根本没有被考虑。为了确保实现是完整和正确的,所
  • 有这些问题都应该被解决。
  • 异常处理还没有得到详尽考虑。
  • 还有待发现的其他问题。

已经考虑的一件事是 shared_ptr 的导出。声明共享指针序列化的头文件包括一些特殊的宏,用于导出 shared_ptr:

BOOST_SHARED_POINTER_EXPORT(T)
BOOST_SHARED_POINTER_EXPORT_GUID(T, K)

这些是用于导出通过原始指针序列化的类的宏的专门版本。

显然,对智能指针进行完整、正确和异常安全的序列化将是一项挑战。我希望这个实现为此类工作提供了一个有用的起点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1008766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(二十七)大数据实战——hbase高可用集群安装与部署

前言 本节内容我们主要介绍HBase高可用集群的安装部署。HBase是一个开源的分布式非关系型数据库管理系统&#xff08;NoSQL&#xff09;&#xff0c;它运行在Apache Hadoop之上。它基于Google的Bigtable论文设计&#xff0c;并且具有高扩展性、高可靠性和高性能的特点。HBase通…

Python 04 之变量【列表,元组,集合,字典,字符串】

&#x1f600;前言 在Python编程语言中&#xff0c;我们经常会遇到各种数据类型和相应的操作方法。理解和掌握这些基本构造是进行有效编程的前提。在本文中&#xff0c;我们将介绍两种非常重要的数据结构 - 集合和字典&#xff0c;然后我们将深入探讨字符串及其相关的操作和处理…

父域 Cookie实现sso单点登录

单点登录&#xff08;Single Sign On, SSO&#xff09;是指在同一帐号平台下的多个应用系统中&#xff0c;用户只需登录一次&#xff0c;即可访问所有相互信任的应用系统。Cookie 的作用域由 domain 属性和 path 属性共同决定。在 Tomcat 中&#xff0c;domain 属性默认为当前域…

CUDA小白 - NPP(8) 图像处理 Morphological Operations

cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化&#xff0c;具体的可以参考别的博主的介绍&#xff0c;都比较详细。还有一些cuda中的专有名词的含义&#xff0c;可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus&#xf…

消除笔哪个P图软件有?这几种软件都有消除笔功能

哪些软件中有消除笔工具呢&#xff1f;我们在日常的生活中&#xff0c;会经常有编辑图片的需求&#xff0c;如果图片上有一些内容我们想要将它去除掉&#xff0c;如文字、涂鸦、笔记、标记等&#xff0c;需要用到一些消除笔工具&#xff0c;那么哪些软件具有这个功能并且还非常…

Excel变天了!国内已经可以用Python了!看看如何操作

对于大部分学python的同学来说&#xff0c;绝大部分场景都是用Pandas处理excel。 但有时简单的处理还要打开Jupyter或者VS Code&#xff0c;就有点麻烦。 现在&#xff01;微软已经把Python塞到Excel里啦&#xff01; 其实之前就已经塞了&#xff0c;但这几天国内都可以用了。…

传猪场员工因抑郁症去世,ACM金牌

前言 一位素未蒙面的学弟&#xff0c;R.I.P 既然是 “传”&#xff0c;我们就不能假定人家有抑郁症&#xff0c;其实前天就收到了这个消息&#xff0c;因为是一个学校的&#xff0c;又是ACM金牌&#xff0c;所以第一时间就在群里刷屏了&#xff0c;这件事情对于一个家庭来说&am…

10个TikTok影响力营销策略,让你的品牌崭露头角

TikTok已经成为一种崭露头角和塑造品牌声誉的强大平台。随着数以亿计的用户在这个短视频应用上分享创意和内容&#xff0c;品牌和营销专业人士也越来越多地将其作为推广产品和服务的渠道。 在本文中&#xff0c;我们将探讨10个TikTok影响力营销策略&#xff0c;帮助你的品牌在…

【Spring Boot】有这一文就够了

作者简介 前言 作者之前写过一个Spring Boot的系列&#xff0c;包含自动装配原理、MVC、安全、监控、集成数据库、集成Redis、日志、定时任务、异步任务等内容&#xff0c;本文将会一文拉通来总结这所有内容&#xff0c;不骗人&#xff0c;一文快速入门Spring Boot。 专栏地址…

了解CRM软件系统三种类型的特点与区别

市面上的CRM系统大致可以分为三种主要类型&#xff1a;分析型CRM、运营型CRM和协作型CRM。很多人对这三种类型的CRM系统不太了解&#xff0c;不知道该如何区分&#xff0c;下面我们就来说说CRM系统的3种类型&#xff1a;分析型、运营型和协作型的区别。 分析型CRM的特点&#…

系统灰度随笔记

系统灰度随笔记 这段时间系统重构&#xff0c;负责重构的其中一个模块需要与四个上游系统对接进行切换&#xff0c;虽然自己在这个过程中也设计了一套灰度方案来承接&#xff0c;将灰度的主动权控制在下游&#xff0c;但是很难同时应对四个上游系统&#xff0c;因为每个上游系…

Python语言学习实战-内置函数reduce()的使用(附源码和实现效果)

实现功能 reduce()是一个内置函数&#xff0c;它用于对一个可迭代对象中的元素进行累积操作。它接受一个函数和一个可迭代对象作为参数&#xff0c;并返回一个单个的累积结果。reduce()函数的语法如下&#xff1a; reduce(function, iterable[, initializer])其中&#xff0c;…

SpringMVC之JSON返回及异常处理

目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 Jackson 定义 用法 常用注解 统一异常处理 为什么要全局异常处理&#xff1f; 异常处理思路 SpringMVC异常分类 综…

java基础-基础知识点

文章目录 jdk目录结构函数式接口wait、notify、notifyAll 并发编程Threadsleep、yield、joindaemon &#xff08;守护线程&#xff09; 锁[synchronized ](https://blog.csdn.net/EnjoyFight/article/details/127457876)线程池 jdk目录结构 jdk1.8 jdk20 函数式接口 http…

PyTorch之张量的相关操作大全 ->(个人学习记录笔记)

文章目录 Torch1. 张量的创建1.1 直接创建1.1.1 torch.tensor1.1.2 torch.from_numpy(ndarray) 1.2 依据数值创建1.2.1 torch.zeros1.2.2 torch.zeros_like1.2.3 torch.ones1.2.4 torch.ones_like1.2.5 torch.full1.2.6 torch.full_like1.2.7 torch.arange1.2.8 torch.linspace…

快速安装Redis以及配置Redis集群

Redis集群 本章是基于CentOS7下的Redis集群教程&#xff0c;包括&#xff1a; 单机安装RedisRedis主从Redis分片集群 1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl#docker安装redis #1、docker pull redis#2、docker run --name my…

如何搭建一款BI系统

一、BI系统介绍 1.1 什么是BI系统 BI的英文全拼是Business Intelligence&#xff0c;商业智能&#xff0c;简称BI。我们经常能听到企业说“上BI”、“建设BI系统”、“构建BI决策平台”等内容。那么BI到底是什么呢&#xff1f; (1) 最初起源于固定报表 在几十年前&#xff…

【网络编程】深入理解TCP协议一(三次握手四次挥手、标记位、确认应答机制、超时重传机制)

TCP协议 1.三次握手四次挥手2.TCP协议段格式3.标记位介绍4.确认应答机制5.超时重传机制 1.三次握手四次挥手 当客户端发起连接请求时&#xff0c;SYN需要被设置位1&#xff0c;告诉服务器客户端希望建立一个链接服务器收到响应之后会回复 SYNACK&#xff0c;表示确认了客户端地…

Hum Brain Mapp:皮质脑-心轴的微状态

摘要 脑电图(EEG)微状态是具有准稳态头皮地形的大脑状态。这种状态是否会延伸到身体层面(即外周自主神经系统)目前尚不清楚。假设微状态作为一种中枢自主神经网络的功能状态会延伸到脑-心轴水平。因此&#xff0c;本研究结合了EEG和心跳动力学序列来估计起源于皮层的定向信息传…

第35章_瑞萨MCU零基础入门系列教程之ADXL345三轴传感器驱动实验

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…