三、资源管理

      资源就是一旦你使用了它,将来不用的时候必须归还系统。C++中最常用的资源就是动态内存分配。其实,资源还有 文件描述符、互斥器、图形界面中的字形、画刷、数据库连接、socket等。

1、        以对象管理资源

      void f()

{

    investment *plv = createInvestment();

    //这里存在很多不定因素,可能造成下面语句无法执行,这就存在资源泄露的可能。

    delete plv;

}

     这里我们把资源放进一个对象里面,然后依赖C++本身的对象里面的析构函数帮我们确保资源被释放。这里用到auto_ptr来解决。这是一个类指针对象,也就是所谓的智能指针。其析构函数自动调用delete。

    std::auto_ptr<Investment> pInv1(createInvestment()); //pInv1指向createInvestment()返回物;
     std::auto_ptr<Investment> pInv2(pInv1);                      //现在pInv2指向对象,而pInv1被设为NULL;
     pInv1 = pInv2;                                                               //现在pInv1指向对象,而pIn2被设为NULL;

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

     还有一个问题就是,不能让多个auto_ptr同时指向某一个对象。auto_ptr还有一个特性就是,通过复制之后,其raw 对象被置为null。

     所以,我们引用一个  引用计数型智能指针  shared_ptr 。它可以持续跟踪共有多少个对象指向某笔资源,并在无人指向它是自动删除该资源。

    void f()

{

    std::   shared_ptr<investment> plv1(createinvestment());//pInv1指向createInvestment()返回物;

    std::   shared_ptr<investment> plv2(plv1);//pInv1,pInv2指向同一个对象;

    plv1 = plv2;//同上,无变化

}//函数退出,pInv1,pInv2被销毁,它们所指的对象也竟被自动释放。

   还有一个问题就是,上面两个智能指针 auto_ptr 与 shared_ptr在析构函数内只执行 delete 而不是delete[] ,也就意味着,在动态分配的数组上这两个指针也存在风险。这个可能就需要使用boost::   shared_array来帮助了。

记住:

      为防止资源泄露,请使用RAII对象,他们在构造函数中获得资源,在析构函数中释放资源。

      两个比较常用的RAII类分别是auto_ptr和shared_ptr.后者通常都是较佳选择,因为其拷贝比较直观。

2、    在资源管理类中小心拷贝行为

       在堆上申请的资源我们可以用上面的智能指针类去管理,但有些并不适合。这时,我们就需要建立自己的资源管理类。

  void lock(Mutex *pm);     //锁定pm所指的互斥量
  void unlock(Mutex *pm);        //将pm解除锁定
  //   我们建立的资源管理类可能会是这样:
     class Lock 
    {
        public: 
        explicit Lock(Mutex *pm)
        : mutexPtr(pm) 
        {
             lock(mutexPtr); 
        } 
        ~Lock() 
        { 
             unlock(mutexPtr); 
        } 
        private: 
        Mutex *mutexPtr; 
    }; 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

   当Lock对象被复制,会发生什么?

通常,我们会选择以下两种解决方案:

1、禁止复制

2、对底层资源使用  引用计数法

通常只要内含一个tr1::shared_ptr成员变量,RAII类便可实现”引用计数“行为。

     class Lock

    {

        public:

            explicit Lock(Mutex *pm)

            : mutexPtr(pm, unlock)        //由于tr1::shared_ptr缺省行为是”当引用计数为0时删除其所指物“,幸运的是                                                          //我们可以指定”引用计数“为9时被调用的所谓”删除器“,即第二个参数unlock

        {

            lock(mutexPtr.get());

        }

        private:

std::tr1::shared_ptr<Mutex> mutexPtr;

     };

     本例中,并没说明析构函数,因为没有必要。编译器为我们生成的析构函数会自动调用其non-static成员变量(mutexPtr)的析构函数。而mutexPtr的析构函数会在互斥量”引用计数“为0时自动调用tr1::shared_ptr的删除器(unlock)。

    Copying函有可能被编译器自动创建出来,因此除非编译器所生成版本做了你想要做的事,否则你得自己编写它们。

    记住:

  • 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。
  • 普遍而常见的RAII类拷贝行为是:抑制拷贝,施行引用计数法。不过其它行为也可能被实现。 

Effective C++ 条款13/14 以对象管理资源 || 在资源管理类中小心拷贝行为的更多相关文章

  1. Effective C++ -----条款13:以对象管理资源

    为防止资源泄漏,请使用RAII(Resource Acquisiton Is Initialization) 对象,它们在构造函数中获得资源并在析构函数中释放资源. 两个常被使用的RAII class ...

  2. 条款13:以对象管理资源(use objects to manage resources)

    NOTE: 1.为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源. 2.两个常被使用的RAII classes 分别是 trl::shared_ptr 和 auto_ ...

  3. effective C++ 读书笔记 条款14 以对象管理资源

    如果我们使用一个投资行为的程序库: #include "stdafx.h" #include <iostream> #include <memory> us ...

  4. Effective C++(14) 在资源管理类中小心copying行为

    问题聚焦:     上一条款所告诉我们的智能指针,只适合与在堆中的资源,而并非所有资源都是在堆中的.     这时候,我们可能需要建立自己的资源管理类,那么建立自己的资源管理类时,需要注意什么呢?. ...

  5. [Effective C++ --014]在资源管理类中小心copying行为

    第一节 <背景> 条款13中讲到“资源取得的时机便是初始化时机”并由此引出“以对象管理资源”的概念.通常情况下使用std中的auto_ptr(智能指针)和tr1::shared_ptr(引 ...

  6. 【14】在资源管理类中小心copying行为

    1.为什么要使用资源管理类? 资源管理类的思路就是,栈上的对象,封装堆上分配的资源,确保一定会释放资源.auto_ptr和shared_ptr就是资源管理类,行为上像指针. 2.auto_ptr和sh ...

  7. EC笔记:第三部分:13、以对象管理资源

    C++相比Java等含有gc的语言来说,内存管理方面(也包括资源管理)比较令人头疼.一些初级程序员,甚至是一些经验丰富的老程序员,也会经常在资源管理上犯错.这时候就需要一个能够自动管理资源的东西(gc ...

  8. 条款14:在资源管理类中小心copying行为

    请牢记: 1.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 2.普遍常见的RAII class copying行为是:抑制copyin ...

  9. EC笔记:第三部分:14、在资源管理类中小心Copying行为

    场景 上一节实现了智能指针,其中的拷贝构造函数和赋值运算符是通过增加/减少指针的引用计数来操作的.但是如果是管理一个独占资源呢?我们希望在一个资源使用时被锁定,在使用完毕后被释放. #include ...

随机推荐

  1. shell-code-4-运算符

    #1. shell 基本运算符有:算数.关系.布尔.字符串.文件测试运算符#2. 原生bash不支持简单的数学运算,可使用awk和expr(最常用)echo `expr 1 + 2`# 反引号:表达式 ...

  2. 误删除innodb ibdata数据文件-之恢复

    今天在群里看到有人说不熟悉innodb把ibdata(数据文件)和ib_logfile(事务日志)文件误删除了.不知道怎么解决.当时我也不知道怎么办.后来查阅相关资料.终找到解决方法.其实恢复也挺简单 ...

  3. linux 安装SNV服务

    1.安装vnc server[root@pxe ~]# yum install tigervnc-server -y 2.设置 vnc server 开机启动[root@pxe ~]# chkconf ...

  4. Centos 6.5升级openssh到7.5p1版本

    centos6自带的ssh版本较低,存在高危漏洞,目前部分服务器需要升级到最新版本(目前是7.5p1). 注:升级ssh存在一定的危险性,一旦不成功可能无法通过远程连接到系统,因此在升级之前最好有远程 ...

  5. Educational Codeforces Round 33 (Rated for Div. 2)

    A. Chess For Three time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  6. 【Luogu】P1306斐波那契公约数(递推)

    题目链接 有个定理叫gcd(f(n),f(m))=f(gcd(n,m)) 所以递推就好了. #include<cstdio> #include<cstdlib> #includ ...

  7. BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法

    发现t非常大,所以大概就是快速幂一类的问题了, 然后根据k^3logn算了算,发现k大约是边数的时候复杂度比较合适. 发现比较麻烦的就是前驱的记录,所以直接把边看做点,不能走反向边,但是可以走重边,然 ...

  8. Java的反射机制和动态代理

    介绍Java注解的时候,多次提到了Java的反射API.与javax.lang.model不同的是,通过反射API可以获取程序在运行时刻的内部结构.反射API中提供的动态代理也是非常强大的功能,可以原 ...

  9. 查看Linux每个进程的流量和带宽

    原文:https://blog.csdn.net/monkeynote/article/details/45867803 作为一个系统管理员,有时候需要搞清楚一台机器上的哪个进程占用了较高的网络带宽. ...

  10. 商务旅行(codevs 1036)

    题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任 ...