智能指针

由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete。程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见。用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法。
智能指针包括包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost::intrusive_ptr。这里主要讲三个常用的。

对于编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命期即将结束时,智能指针通过析构函数释放有它管理的堆内存。所有智能指针都重载了“operator->”操作符,直接返回对象的引用,用以操作对象。访问智能指针原来的方法则使用“.”操作符。访问智能指针包含的裸指针则可以用 get() 函数。由于智能指针是一个对象,所以if (my_smart_object)永远为真,要判断智能指针的裸指针是否为空,需要这样判断:if (my_smart_object.get())。

1、auto_ptr

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。RAII 的一般做法是这样的:在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
①不需要显式地释放资源。
②采用这种方式,对象所需的资源在其生命期内始终保持有效。
此时,所托管的资源,随对象的创建而获取,随对象的消失而消失,即所谓的 RAII 思想:资源获取即初始化。

#include <iostream>
#include <memory>//使用auto_ptr要包含此头文件
using namespace std;
class A
{
public:
    A()
    {
          cout<<"A()"<<endl;
     }
    ~A()
    {
        cout<<"~A()"<<endl;
    }
    void dis()
    {
        cout<<"A::void dis()"<<endl;
    }
};
void func()
{
    auto_ptr<A> a(new A);
    a->dis();
}
int main()
{
    func();
    return 0;
}

原理上,是代理了被托管的对象指针,管理对象的生命周期,即实现自动释放。其行为类似于所托管的对象指针,原因是,重载了 operator->和 operator*。

auto_ptr可以实现拷贝,也就是让两个智能指针指向了同一块内存,然后在后面释放的时候,在某些编译器中此时编译很有可能会导致程序崩溃,所以要谨慎使用哦。
注意:不要讲auto_ptr对象存储在容器中,不要使用auto_ptr对象保存动态分配数组的指针,不要使用auto_ptr对象保存指向静态分配对象的指针。

(1) auto_ptr的构造函数为explicit,阻止了一般指针隐式类型转换为auto_ptr的构造,所以如下的创建方式是编译不过的。
(2) 由于auto_ptr对象析构时会删除它所拥有的指针,所以使用时避免多个auto_ptr对象管理同一个指针。如下的使用方法应该避免。
(3)auto_ptr的内部实现中,析构函数中删除对象使用delete而不是delete[],所以auto_ptr不能用来管理数组指针。
(4)C++中对一个空指针NULL执行delete操作是安全的。所以在auto_ptr的析构函数中无须判断它所拥有指针是否为空。
(5) C++的STL容器对于容器元素类型的要求是有值语义,即可以赋值和复制。auto_ptr在赋值和复制时都进行了特殊操作,所以auto_ptr对象不能作为STL容器元素。

2、unique_ptr

uniqu_ptr 的使用方法,基本上等同于 auto_ptr, 不同之处,就在于实现了资源的唯一, 既不可以拷贝也不可以赋值,正如其名字一样。
![](https://i.loli.net/2019/09/23/fnLzdyxqMkHZ59G.jpg)

注意这个release 是对所托管的对象,释放权限,并没有释放托管对象本身。

3、shared_ptr

uinque_ptr 解决了 auto_ptr 中引用同一个对象的问题,方式就是不可引用同一个对象。
shared_ptr 解决了 auto_ptr 中引用同一个对象,共同拥有一个资源, 但不会重析构的问题,原理是,在内部保持一个引用计数,并且仅当引用计数为 0 才能被删除,不可以用数组。(但是unique_ptr是可以用数组的。)
正因为如此,我们用shared_ptr情况更多。

#include <iostream>
#include <memory>
using namespace std;
void func(shared_ptr<int> sp)
{
    // sp.reset(); //此处仅将自己所累积的计数减 1
    cout<<sp.use_count()<<endl;
    sp.reset(); //此时 reset 等价于 sp 对象消失,若己为零则不再减 1.
}
int main()
{
    shared_ptr<int> sp(new int(10));
    cout<<sp.get()<<endl;
    if(sp)
         cout<<"有资源托管中"<<endl;
}

注意这段程序,reset只是将自己累积的技术减去1。

Last modification:October 6th, 2019 at 04:02 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment