effective c++条款13

所谓资源就是,一旦用了它,将来必须还给系统
c++最常使用的资源就是动态分配内存,但内存只是你必须管理的众多资源之一,其他常见的资源还包括文件描述器,互锁器,图形界面中的画笔,画刷,字型,数据库连接,网络socket等等

RAII是Resource Acquisition Is Initialization的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源

现在进入正文:
1.为防止资源泄露,请使用RAII对象,他们在构造函数中获得资源,在析构函数中释放资源
2.两个常使用RAII对象类是shared_ptr和auto_ptr,前者通常是较佳选择,其copy行为比较直观(复制后,两个RAII对象指向的是同一个资源),auto_ptr复制后,会发生所有权的转让(复制动作,会使前一个RAII对象指向NULL)

假设有这样的类

class People
{
    friend ostream& operator<<(ostream& out, const People& p)
    {
        out << p.m_name << " " << p.m_age;
        return out;
    }
public:
    People(string name, int age) :m_name(name), m_age(age){}
    ~People(){ cout << "执行People对象的析构函数" << endl; }
    People(const People& rhs) :m_name(rhs.m_name), m_age(rhs.m_age){}
    People& operator=(const People& rhs)
    {
        if (this == &rhs)
            return *this;
        this->m_name = rhs.m_name;
        this->m_age = rhs.m_age;
        return *this;
    }
private:
    string m_name;
    int m_age;
};

一个人出生就注定了死亡,所以,我们可以写这样一个函数

void f()
{
    People* pl=new People("XXX",20);
    ...
    delete People;
}

这里就可能存在问题,可能在delete之前就有return,goto语句,或者delete之前的语句抛出异常,这样就没有可能去执行delete语句了,总而言之,由于各种可能的原因,这个函数不是很可靠

为确保heap上分配的People对象的资源总是被释放,我们需要将它放进另一个管理类对象中,当控制流离开People对象的块区域中,该管理对象的析构函数会自动释放
代码如下

#include<windows.h>
#include <iostream>
#include <memory>
#include <string>
using namespace std;

int main()
{
    {
        auto_ptr<People>m_ptr1(new People("dyy", 27));
        cout << *m_ptr1 << endl;
        auto_ptr<People>m_ptr2 = m_ptr1;
        if (m_ptr1.get() == NULL)
        {
            cout << "指针为空" << endl;
        }
    }
    system("pause");
    return 0;
}

这段代码运行结果:
执行People对象的析构函数

当然auto_ptr的复制特性比较特殊,发生复制时,前一个auto_ptr会失去对象资源
还有shared_ptr可以使用,它的复制特性就比较正常,采用引用计数,复制之后,多个shared_ptr指向同一个对象资源

另外没有针对C++动态分配数组而设计的auto_ptr和shared_ptr(auto_ptr和shared_ptr采用的是delete,而不是delete[]),boost苦中有对应该需求的指针

猜你喜欢

转载自blog.csdn.net/baidu_25539425/article/details/79939386