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

C/C++|经典代码题(动态资源的双重释放与「按值传递、按引用传递、智能指针的使用」)

以下代码中你能看出其存在什么问题?如何修复,能给出几种方法?分别在什么场景下用哪种方法。

#include <iostream>class Buffer {public:Buffer() { std::cout << "Buffer created" << std::endl; }~Buffer() { std::cout << "Buffer destroyed" << std::endl; }Buffer(const Buffer&) = delete;Buffer& operator=(const Buffer&) = delete;
};class BufferManager {public:BufferManager() : buffer(new Buffer()) {std::cout << "BufferManager created" << std::endl;}~BufferManager() {std::cout << "BufferManager destroyed" << std::endl;delete buffer;}private:Buffer* buffer;
};void getBuffer(BufferManager manager) {std::cout << "Call getBuffer" << std::endl;
}int main() {BufferManager manager;getBuffer(manager);return 0;
}

代码简单介绍如下:给出两个类,一个是 buffer 管理器,底层是 buffer, buffer 管理器持有一个 buffer 指针,有一个 getBuffer 函数。主逻辑也很简单,就是构造 BufferManager,调用 getBuffer

我们简单分析一下代码:

我们在 getBuffer 中,是按值传递 BufferManager 对象,这会导致 BufferManager 对象被拷贝。然而, BufferManager 对象中报一个只想动态分配内存的 buffer ,并且 BufferManager 的默认拷贝构造函数只是执行浅拷贝。这样,多个 BufferManager 对象会共享同一个 Buffer 对象指针。当它们被销毁时,析构函数会多次尝试删除同一个指针,导致双重释放错误。

拷贝构造函数和赋值运算符的隐式生成会默认浅拷贝!!这对于类中包含指针成员时,通常会导致资源管理问题。

方案一:禁止拷贝构造和赋值操作

主要场景: 如果 BufferManager 作为资源的唯一拥有者,不应允许拷贝,则可以直接禁止拷贝构造函数和赋值操作符。这样就可以避免拷贝行为带来的问题。

class BufferManager {public:BufferManager() : buffer(new Buffer()) {std::cout << "BufferManager created" << std::endl;}~BufferManager() {std::cout << "BufferManager destroyed" << std::endl;delete buffer;}// 禁止拷贝构造和赋值操作BufferManager(const BufferManager&) = delete;BufferManager& operator=(const BufferManager&) = delete;private:Buffer* buffer;
};

通过禁止拷贝和赋值操作,BufferManager 对象无法被复制,因此也不会出现指针重复管理的问题。在需要确保对象不可拷贝的场景下使用这种方法非常合适,例如管理独占资源时。

方式二:按引用传递 BufferManager(最普遍、广泛的改进)

场景:如果只需要传递 BufferManager 的引用,而不需要拷贝整个对象,可以使用按引用传递的方式。这可以避免对象的拷贝,消除双重释放的风险

void getBuffer(BufferManager& manager) {}

方式三:使用智能指针(也是一种普遍、广泛的改进)

场景:如果希望让对象能够被安全地复制和转移,并且自动管理指针的生命周期,可以使用 std::unique_ptr 代替原始指针。std::unique_ptr 能够确保指针只被释放一次,并且不会导致双重释放问题。

我们将 BufferManager 中的原始指针替换为 std::unique_ptr,这样当 BufferManager 被销毁时,智能指针会自动管理 Buffer 对象的销毁。

#include <memory>class BufferManager {public:BufferManager() : buffer(std::make_unique<Buffer>()) {std::cout << "BufferManager created" << std::endl;}~BufferManager() {std::cout << "BufferManager destroyed" << std::endl;}private:std::unique_ptr<Buffer> buffer;
};
http://www.lryc.cn/news/428478.html

相关文章:

  • 西北乱跑娃 -- linux使用笔记
  • Kubectl基础命令使用
  • 推荐编译器插件:Fitten Code 更快更好的AI助手
  • ArcGIS Pro基础:状态栏显示栏的比例尺设置和经纬度位置
  • 微前端架构入门
  • [LitCTF 2023]导弹迷踪
  • win10安装wsl2(ubuntu20.04)并安装 TensorRT-8.6.1.6、cuda_11.6、cudnn
  • 信息搜集--敏感文件Banner
  • Qt 学习第六天:页面布局
  • 利用队列收集单双击和长按按键
  • AI工作流:低代码时代的革新者,重塑手机问答类应用生态
  • 配置MySQL主从,配置MySQL主主 +keeplive高可用
  • 第5节:Elasticsearch核心概念
  • 存储实验:华为异构存储在线接管与在线数据迁移(Smart Virtualization Smart Migration 特性)
  • 职业院校云计算实训室建设方案全景剖析
  • VS Code安装与vue项目新建
  • 如何在Java中将数据库查询结果转换为枚举类型
  • 秋招突击——8、20——知识补充——Java容器
  • IOS 06 OC调用Swift第三方框架
  • SAP和致远OA系统集成案例
  • 19 OptionMenu 组件
  • 【C语言】字符函数与字符串函数(上)
  • 机器学习系列—深入探索弗里德曼检验:非参数统计分析的利器
  • 【ubutnu18.04】k8s 部署4: worker节点配置1.31.0和containerd 1.7.20
  • android kotlin集成WorkManager实现定时获取数据
  • BvSP_ Broad-view Soft Prompting for Few-Shot Aspect Sentiment Quad Prediction
  • React+Vis.js(05):vis.js的节点的点击事件
  • 今日(2024 年 8 月 19 日)科技新闻
  • Python 虚拟环境
  • Redis RDB三两事