热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EffectiveC++随笔13to17资源管理

资源管理并不单指内存,这里的资源包括内存、文件描述器、互斥锁、图形界面中的字形与笔刷、数据库连接、网络sockets等,其中最常用的是内存资源。13.以对象管理资源为防止资源泄露的



资源管理并不单指内存,这里的资源包括内存、文件描述器、互斥锁、图形界面中的字形与笔刷、数据库连接、网络sockets等,其中最常用的是内存资源。


13.以对象管理资源

为防止资源泄露的一个简单方法是:使用RAII对象,(资源取得即初始化),通常在构造函数中分配资源,在析构函数中释放资源。这样做带来的好处是:对象在离开作用域时,会隐式调用析构函数,将内存释放,不必担心忘记将资源释放及提早return或出现异常导致资源未释放的问题。

RAII的一个例子是智能指针auto_ptr,智能指针的一个特点是:由于智能指针被销毁时会自动释放指向的内存,因此不允许两个指针指向同一块内存。在指针赋值时,ptr1=ptr2,ptr1接受ptr2的赋值后,ptr2会变成NULL,ptr1拥有该资源的唯一控制权,这一特性不同于普通指针。

若要完成两个指针指向同一内存的功能,可以使用shared_ptr,称为引用技术性智慧指针(RCSP),它追踪共有多少对象指向某笔资源,并在无人指向时释放该资源。

值得说明的一点是:使用智能指针完成动态分配数组是一个糟糕的想法,因为智能指针析构时调用的是delete而非delete[ ],这将只释放掉数组的头指针,而数组内存无法释放。若你有该需求,使用vector是个好的选择。


14.资源管理类中小心copy行为

复制RAII对象必须一并复制它所管理的资源,所以资源的copy行为决定了RAII对象的copy行为。当一个RAII对象被复制时,我们通常会考虑下面的策略:

(1)禁止复制

对于一些RAII对象,对其进行复制操作事实上并不合理(如互斥锁),此时我们应该禁止复制,实现方法之前有详述(重载复制构造函数设为private)。

(2)对底层资源使用“引用计数法”

有时候我们希望保留某资源,直至其最后一个调用者被销毁,类似于shared_ptr的机制。

这里的shared_ptr允许指定第二个参数,将一函数作为删除器,在调用者计数为零时,将会调用该删除器完成相应功能(本例中是解开互锁)



(3)复制底部资源

这要求复制时不仅复制资源管理对象,同时也复制其所包覆的资源。这种复制方式称为“深拷贝”。

(4)转移底部资源

auto_ptr是一个典型。


15.在资源管理类中提供对原始资源的访问

RAII给我们提供了一种管理内存的机制,但有时我们经常会遇到需要访问原始资源的问题,因此每一个RAII类应当提供一种访问其原始资源的方法如get()函数。对原始资源的访问可能经由显式转换或隐式转换,一般来说显式转换比较安全,但隐式转换对用户来说比较方便。

在这里插入图片描述

在这里插入图片描述


16.成对使用new和delete时要采取相同形式

delete与new一一匹配,delete[ ]与new一个数组一一匹配。

(来自C++ primer)

当new函数运行时,实际上发生三个步骤:

1.调用operator new的标准库函数,分配足够大的原始未类型化的内存,以保存指定类型的一个对象。

2.运行该类型的一个构造函数,使用指定初始化式构造对象

3.返回指向新分配并构造对象的指针

当delete函数运行时,实际上发生两个步骤:

1.对指针指向的对象调用适当的析构函数

2.调用operator delete的标准库函数释放对象使用的内存


17.以独立语句将newd对象置入智能指针

在这里插入图片描述

为什么上图的做法不是一个好的选择?

因为按需要本应按下图的顺序执行工作:

在这里插入图片描述

但C++并未定义其顺序,编译器完全可能以下面的顺序完成在这里插入图片描述

此时问题出现了,若第二步出现异常,则第三步不会运行,作为唯一能够控制该内存的智能指针并未建立,该块内存将永远不能被我们访问与释放。

因此我们应当将使用独立语句将其置入智能指针,以避免出现异常导致句柄丢失影响内存释放。

在这里插入图片描述



推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文对SQL Server系统进行了基本概述,并深入解析了其核心功能。SQL Server不仅提供了强大的数据存储和管理能力,还支持复杂的查询操作和事务处理。通过MyEclipse、SQL Server和Tomcat的集成开发环境,可以高效地构建银行转账系统。在实现过程中,需要确保表单参数与后台代码中的属性值一致,同时在Servlet中处理用户登录验证,以确保系统的安全性和可靠性。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 在Linux系统中避免安装MySQL的简易指南
    在Linux系统中避免安装MySQL的简易指南 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • 本文详细解析了Java类加载系统的父子委托机制。在Java程序中,.java源代码文件编译后会生成对应的.class字节码文件,这些字节码文件需要通过类加载器(ClassLoader)进行加载。ClassLoader采用双亲委派模型,确保类的加载过程既高效又安全,避免了类的重复加载和潜在的安全风险。该机制在Java虚拟机中扮演着至关重要的角色,确保了类加载的一致性和可靠性。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 本文详细介绍了如何在 Django 项目中使用 Admin 管理后台,包括创建超级用户、启动项目、管理数据模型和修改用户密码等步骤。 ... [详细]
  • 在 Ubuntu 中遇到 Samba 服务器故障时,尝试卸载并重新安装 Samba 发现配置文件未重新生成。本文介绍了解决该问题的方法。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
author-avatar
天蝎快乐公主_594
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有