智能指针

由于 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。

版权属于:孟超 本文链接:https://mengchao.xyz/index.php/archives/518/ 转载时须注明出处及本声明

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++11、STL面试题

    C++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被1...

    用户5426759
  • C++类的拓展

    对于类的大小,发现成员函数并不用类的存储空间。 只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。 所有的对象都调用共用...

    用户5426759
  • C++11—给时代一个新选择

    C++11是新时代的C++亦称为modern C++,是对C++98扩展。C++11旨在手写简便与提高效率。C++11实现了more concise ,more...

    用户5426759
  • 通俗易懂学习C++智能指针

    智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。

    海盗船长
  • leveldb uint32压缩方法

    leveldb 采用 protocalbuffer 里使用的变长整形编码方案,以节省空间;

    awk
  • STL四种智能指针

    STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr,auto_ptr是C++98提供的解决方案,...

    Dabelv
  • 序列中查找第二小元素

    序列中查找第二小元素有很多方法,本文介绍的是采用分治的思想,自底向上,序列中两两构成一对,比较选出最小值,然后构成上一层序列,然后依次网上构造,最后,根节点就是...

    chain
  • C++栈展开如何防止内存泄露

    在栈展开(stack unwinding)是指,如果在一个函数内部抛出异常,而此异常并未在该函数内部被捕捉,就将导致该函数的运行在抛出异常处结束,所有已经分配在...

    Dabelv
  • Python爬虫学习-抓取百度百科python词条页面的所有词条及其连接

    这几天我学习爬虫有点过于激进,妄想一鼓作气地学会爬虫,结果随便踩进一个坑就跳不出来了。郁闷了一天,最终发现还是自己的基础太差,比如基础的函数、文件输出等都没有掌...

    爱吃西瓜的番茄酱
  • 【RL-TCPnet网络教程】第32章 RL-TCPnet之Telnet服务器

    本章节为大家讲解RL-TCPnet的Telnet应用,学习本章节前,务必要优先学习第31章的Telnet基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的...

    armfly

扫码关注云+社区

领取腾讯云代金券