尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

item13--使用对象管理资源

item13--使用对象管理资源
📅 发布时间:2026/6/20 6:30:14

简单来说,不要手动去 delete 指针或释放资源,而是把资源放进一个对象里,依靠对象的析构函数(Destructor)自动释放资源。

以下是该条款的详细深度解析,结合了原书内容与现代 C++(C++11 及以后)的最佳实践。


1. 为什么我们需要“以对象管理资源”?

传统做法的缺陷

假设我们有一个工厂函数,用于创建一个 Investment(投资)对象:

Investment* createInvestment(); // 返回指针,指向动态分配的对象

传统的调用方式如下:

void f() {Investment* pInv = createInvestment(); // 1. 获取资源// ... 执行一些操作 ...delete pInv;                           // 2. 显式释放资源
}

潜在的风险: 如果在“执行一些操作”的过程中发生了以下情况,delete pInv 永远不会被执行,从而导致内存泄漏:

  1. 提前返回(Early return):代码逻辑中有一个 return 语句。
  2. 抛出异常(Exception):中间的代码抛出了异常,栈展开(Stack unwinding)跳过了 delete。

解决方案:RAII

C++ 保证:当一个对象离开作用域(Scope)时,其析构函数会被自动调用。

因此,我们将资源(pInv)包装在一个局部对象中。当函数 f() 结束时,局部对象自动销毁,其析构函数负责调用 delete。


2. 核心原则 (RAII 的两大铁律)

Scott Meyers 在书中总结了两个关键点:

  1. 获得资源后立刻放进管理对象 (Resource Acquisition Is Initialization)
    • 当我们调用 createInvestment() 拿到指针的那一刻,应该立刻把它传递给智能指针的构造函数。
    • 不要让裸指针在外面“裸奔”。
  2. 管理对象运用析构函数确保资源被释放
    • 无论控制流是如何离开作用域的(正常结束、break、return、throw),析构函数都会被调用,从而保证资源不泄漏。

3. 书中介绍的工具与现代演变

《Effective C++》成书较早,书中主要介绍了 std::auto_ptr 和 tr1::shared_ptr。在现代 C++ (C++11+) 中,情况发生了变化。

A. std::auto_ptr (已废弃/移除)

  • 书中的描述:它是早期的智能指针,当它被复制时(通过 copy 构造或 copy assignment),它会转移所有权,原来的指针变成 null。
  • 现代观点:绝对不要再使用 auto_ptr。它在 C++11 中被标记为废弃,在 C++17 中已被彻底移除。它的“复制即转移”语义非常容易导致 Bug(例如在 STL 容器中使用会导致未定义行为)。
  • 替代者:std::unique_ptr。

B. std::unique_ptr (现代首选)

这是 auto_ptr 的完美继任者。

  • 语义:专属所有权(Exclusive Ownership)。同一时间只能有一个 unique_ptr 指向该对象。
  • 特点:禁止复制(Copy),只允许移动(Move)。这完美契合了“独占”的逻辑,且性能几乎等同于裸指针。

代码示例:

#include <memory>void f() {// 使用 unique_ptr 管理资源std::unique_ptr<Investment> pInv(createInvestment()); // ... 做任何操作 ...// ... 哪怕抛出异常 ...} // 函数结束,pInv 离开作用域,自动调用 delete

C. std::shared_ptr (引用计数)

书中提到了 RCSP (Reference-counting smart pointer)。

  • 语义:共享所有权。多个指针可以指向同一个对象。
  • 原理:内部维护一个引用计数器。
    • 复制时,计数 +1。
    • 析构时,计数 -1。
    • 当计数变为 0 时,真正的 delete 被调用。
  • 适用场景:当多个对象需要共享底层资源,且无法确定谁最后使用完该资源时。

4. 这里的“资源”不仅仅是内存

虽然本条款主要用内存(指针)举例,但 RAII 适用于所有必须释放的资源:

  • 文件句柄 (File descriptors)
  • 互斥锁 (Mutex locks)
  • 数据库连接 (Database connections)
  • 网络套接字 (Network sockets)

例子:管理互斥锁 不要手动 lock() 和 unlock():

void strictCode() {std::mutex m;std::lock_guard<std::mutex> lock(m); // 构造时 lock// ... 操作共享数据 ...
} // 作用域结束,lock 析构,自动 unlock

5. 特别警示:关于数组

条款 13 特别提到一点:智能指针默认的删除器是 delete,而不是 delete[]。

如果你这样做(在老式 C++ 中):

std::auto_ptr<std::string> aps(new std::string[10]); // 错误!

当 aps 析构时,它会执行 delete 而不是 delete[],导致未定义行为(通常是内存泄漏或崩溃)。

现代 C++ 的建议:

  1. 优先使用 std::vector 或 std::string:它们内部已经封装了数组管理的逻辑,几乎不需要手动 new 数组。

  2. 如果非要用智能指针管理数组,C++11 后的 unique_ptr 支持数组特化:

    std::unique_ptr<int[]> up(new int[10]); // 正确,会自动调用 delete[]
    

总结

条款 13 的核心教义是:为了防止资源泄漏,请使用 RAII 对象。

对于现代 C++ 开发者 (你) 的行动指南:

  1. 默认使用 std::unique_ptr:如果资源是独占的。
  2. 需要共享时使用 std::shared_ptr:如果资源需要在多个拥有者之间共享。
  3. 永远不要使用 std::auto_ptr。
  4. 优先使用标准容器 (vector, string) 代替动态分配的数组 (new T[])。

相关新闻

  • sub_match
  • python django flask酒店客房管理系统数据可视化分析系统_gq8885n3--论文md5
  • python django flask鹿幸公司员工食堂在线点餐餐饮餐桌预约管理系统的设计与实现_utcnqqs0--论文

最新新闻

  • 告别经典游戏兼容性问题:DDrawCompat的智能解决方案
  • 供应链攻击深度剖析:从CVE-2026-8398事件看软件分发安全与防御
  • 2026年洛阳市PMP培训机构哪家好?官方授权R.E.P.报考指南 - 众智商学院课程中心
  • LPC229x ARM7微控制器深度解析:多路CAN、Flash编程与稳定性设计
  • HTTPLeaks:单文件Web安全靶场与浏览器信息泄露原理剖析
  • 嵌入式指令压缩技术:MPC562/564硬件解压原理与工程实践

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号