当前位置: 首页 > news >正文

C++ 中的序列化和反序列化

一、C++ 中的序列化和反序列化

(一)基本概念

在 C++ 中,序列化是将对象转换为字节流的过程,反序列化则是从字节流重新构建对象的过程。这对于存储对象状态到文件、网络传输等场景非常有用。

(二)简单的序列化和反序列化实现方式

1. 基于文本格式

  • 序列化
    • 一种简单的方法是将对象的成员变量以特定的格式(如 CSV - 逗号分隔值)写入文件。例如,假设有一个Person类,包含姓名和年龄两个成员变量。
      #include <iostream>
      #include <fstream>
      #include <string>


      class Person {
      public:
          std::string name;
          int age;
          Person(const std::string& n, int a) : name(n), age(a) {}
      };


      void serializeToText(const Person& p, const std::string& filename) {
          std::ofstream file(filename);
          if (file.is_open()) {
              file << p.name << "," << p.age << std::endl;
              file.close();
          } else {
              std::cerr << "无法打开文件进行序列化。" << std::endl;
          }
      }
  • 反序列化
    Person deserializeFromText(const std::string& filename) {
        std::ifstream file(filename);
        Person p("", 0);
        if (file.is_open()) {
            std::string line;
            if (std::getline(file, line)) {
                size_t pos = line.find(',');
                if (pos!= std::string::npos) {
                    p.name = line.substr(0, pos);
                    p.age = std::stoi(line.substr(pos + 1));
                }
            }
            file.close();
        } else {
            std::cerr << "无法打开文件进行反序列化。" << std::endl;
        }
        return p;
    }

2. 使用二进制格式(更高效,但不可读)

  • 序列化
    • 使用fstream库的二进制模式来写入对象的内存表示。不过需要注意字节序等问题。
      void serializeToBinary(const Person& p, const std::string& filename) {
          std::ofstream file(filename, std::ios::binary);
          if (file.is_open()) {
              // 先写入姓名长度
              int nameLength = p.name.length();
              file.write(reinterpret_cast<const char*>(&nameLength), sizeof(int));
              // 再写入姓名内容
              file.write(p.name.c_str(), nameLength);
              // 写入年龄
              file.write(reinterpret_cast<const char*>(&p.age), sizeof(int));
              file.close();
          } else {
              std::cerr << "无法打开文件进行二进制序列化。" << std::endl;
          }
      }
  • 反序列化
    Person deserializeFromBinary(const std::string& filename) {
        std::ifstream file(filename, std::ios::binary);
        Person p("", 0);
        if (file.is_open()) {
            // 先读取姓名长度
            int nameLength;
            file.read(reinterpret_cast<char*>(&nameLength), sizeof(int));
            char* buffer = new char[nameLength + 1];
            // 读取姓名内容
            file.read(buffer, nameLength);
            buffer[nameLength] = '\0';
            p.name = buffer;
            delete[] buffer;
            // 读取年龄
            file.read(reinterpret_cast<char*>(&p.age), sizeof(int));
            file.close();
        } else {
            std::cerr << "无法打开文件进行二进制反序列化。" << std::endl;
        }
        return p;
    }

(三)使用第三方库(如 Boost.Serialization)进行序列化和反序列化

  • 安装和配置 Boost 库
    • 首先需要下载并安装 Boost 库,这通常涉及从 Boost 官方网站获取源代码,然后通过编译安装到系统中。安装过程因操作系统而异。
  • 使用示例
    • 以下是使用 Boost.Serialization 对Person类进行序列化和反序列化的简单示例。

      #include <iostream>
      #include <fstream>
      #include <boost/archive/text_oarchive.hpp>
      #include <boost/archive/text_iarchive.hpp>
      #include <boost/serialization/string.hpp>


      class Person {
      public:
          std::string name;
          int age;
          Person(const std::string& n, int a) : name(n), age(a) {}
          // 为了让Boost.Serialization能够访问私有成员,需要添加这两个友元函数
          friend class boost::serialization::access;
          template<class Archive>
          void serialize(Archive& ar, const unsigned int version) {
              ar & name;
              ar & age;
          }
      };


      void serializeWithBoost(const Person& p, const std::string& filename) {
          std::ofstream file(filename);
          if (file.is_open()) {
              boost::archive::text_oarchive oa(file);
              oa << p;
              file.close();
          } else {
              std::cerr << "无法打开文件进行Boost序列化。" << std::endl;
          }
      }


      Person deserializeWithBoost(const std::string& filename) {
          std::ifstream file(filename);
          Person p("", 0);
          if (file.is_open()) {
              boost::archive::text_iarchive ia(file);
              ia >> p;
              file.close();
          } else {
              std::cerr << "无法打开文件进行Boost反序列化。" << std::endl;
          }
          return p;
      }

二、C++ 中的对象生命周期管理

(一)对象生命周期阶段

  • 创建
    • 栈对象:在函数内部定义的对象,当程序执行到对象定义处时,会调用对象的构造函数进行创建。例如Person p("Alice", 30);,这里p是一个栈对象,它的生命周期从定义处开始,到所在的代码块结束(如函数返回)。
    • 堆对象:通过new关键字在堆上分配内存创建对象。例如Person* p = new Person("Bob", 25);,此时需要手动管理内存,使用delete来释放内存。
  • 使用:在对象的生命周期内,可以通过对象的成员函数访问和修改对象的状态,就像p->getName()p.setName("Charlie");这样的操作。
  • 销毁
    • 栈对象:当栈对象所在的代码块结束时,对象的析构函数会被自动调用,用于清理对象占用的资源。
    • 堆对象:需要手动调用delete来释放堆上对象占用的内存,并且在调用delete后,对象的析构函数会被调用。如果忘记调用delete,就会导致内存泄漏。

(二)内存管理和资源清理

  • RAII(Resource Acquisition Is Initialization)
    • 这是 C++ 中一种重要的资源管理机制。核心思想是将资源的获取和初始化放在构造函数中,将资源的释放放在析构函数中。例如,使用std::unique_ptrstd::shared_ptr来管理动态分配的内存。
    • // 不需要手动释放内存,当p离开作用域时,Person对象会被自动销毁
    • std::shared_ptr是共享所有权的智能指针,用于多个对象共享同一个资源的情况。例如,多个对象可能需要共享对同一个数据库连接对象的引用。
      手动内存管理(使用
      newdelete
    • 当使用new在堆上分配内存时,必须在适当的时候使用delete来释放内存。错误地使用delete(如多次删除同一个对象或者使用已经删除的对象)会导致程序出错,如段错误等。并且如果在delete之后还尝试访问对象成员,也是未定义行为。
http://www.lryc.cn/news/505467.html

相关文章:

  • 我的Github学生认证申请过程
  • 信奥题解:勾股数计算中的浮点数精度问题
  • 重生之我在学Vue--第2天 Vue 3 Composition API 与响应式系统
  • 【AI知识】逻辑回归介绍+ 做二分类任务的实例(代码可视化)
  • Mysql 笔记2 emp dept HRs
  • MySQL和Oracle的区别
  • 实验12 C语言连接和操作MySQL数据库
  • 09篇--图片的水印添加(掩膜的运用)
  • sql-labs(21-25)
  • CTF知识集-命令执行
  • 基于米尔全志T527开发板的OpenCV进行手势识别方案
  • Htpp中web通讯发送post(上传文件)、get请求
  • 【论文阅读笔记】HunyuanVideo: A Systematic Framework For Large Video Generative Models
  • SpringBoot的事务钩子函数
  • 源码安装PHP-7.2.19
  • UE5制作伤害浮动数字
  • 学习日志024--opencv中处理轮廓的函数
  • (2024年最新)Linux(Ubuntu) 中配置静态IP(包含解决每次重启后配置文件失效问题)
  • DPDK用户态协议栈-TCP Posix API 2
  • [IT项目管理]项目时间管理(本章节3w字爆肝)
  • 【python因果库实战5】使用银行营销数据集研究营销决策的效果5
  • 【Qt】QWidget中的常见属性及其功能(二)
  • 9 OOM和JVM退出。OOM后JVM一定会退出吗?
  • 学习笔记070——Java中【泛型】和【枚举】
  • 【工具变量】碳排放市场交易数据(2013-2023年)
  • 【视频生成模型】——Hunyuan-video 论文及代码讲解和实操
  • 基线检查:Windows安全基线.【手动 || 自动】
  • uniapp跨端适配—条件编译
  • 【Java基础面试题013】Java中静态方法和实例方法的区别是是么?
  • C语言入门(一):A + B _ 基础输入输出