四种智能指针:auto_ptr,unique_ptr,shared_ptr,weak_ptr

stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针的使用总结

(1)auto_ptr

主要用于解决资源自动释放的问题。防止用户忘记delete掉new申请的内存空间。使用auto_ptr会在离开变量的作用域之后直接调用析构函数进行资源释放。

void Function()

{

    auto_ptr<Obj> ptr(new Obj(20));

    ...

    if (error occur)

         throw exception...

}

但是,这是一种被c++11标准废弃的一个智能指针,原因是一旦将autoptr对象赋值给另一个对象,原来的智能指针所指的将是空的地址。再使用该指针就是错误的了。

(2)unique_ptr

unique_ptr指针可以看成auto_ptr的替代品。因为他对对象的引用是唯一的,不能随便进行转移。这种专一是通过无法进行unique_ptr对象的赋值和拷贝构造来实现的。

另外,unique_ptr可以进行移动构造和移动赋值操作。

如果一定要用unique_ptr实现auto_ptr的功能,也就是一定要把一个unique_ptr赋值给另一个,那就一定要通过移动函数来实现。由于是手动操作,因此需要程序员格外注意。

unique<Obj> ptr1(new Obj());

unique<Obj> ptr2(std::move(ptr1));

(3)shared_ptr

auto_ptr和unique_ptr都只能一个智能指针引用对象,而shared_ptr则是可以多个智能指针同时拥有一个对象。

shared_ptr实现方式就是使用引用计数。引用计数的原理是,多个智能指针同时引用一个对象,每当引用一次,引用计数加一,每当智能指针销毁了,引用计数就减一,当引用计数减少到0的时候就释放引用的对象。这种引用计数的增减发生在智能指针的构造函数,复制构造函数,赋值操作符,析构函数中。

这种方式使得多个智能指针同时对所引用的对象有拥有权,同时在引用计数减到0之后也会自动释放内存,也实现了auto_ptr和unique_ptr的资源释放的功能。

由于shared_ptr支持复制构造,所以它可以作为标准库容器中的元素。这是auto_ptr和unique_ptr所不能实现的。

(4)weak_ptr

shared_ptr是一种强引用的关系,智能指针直接引用对象。那么这个会代码一个隐含的问题,就是循环引用,从而造成内存泄漏,即便是java语言有自己的垃圾回收器,对这种内存泄漏也没有办法,所以循环引用对java程序员来说也是一个很值得注意的问题。首先来看一个循环引用的例子。

class Parent {

public:

    shared_ptr<Child*> child;

};

class Child {

public:

    shared_ptr<Parent*> parent;

};

void Function(){

    shared_ptr<Parent*> pA(new Parent); //Parent的引用计数为1

    shared_ptr<Child*> pB(new Child); //Child引用计数为1

    pA->child = pB; //使用了赋值函数,因此Child引用计数增加1,变为2

    pB->parent = pA; //使用了赋值函数,因此Parent引用计数增加1,变为2

// pB先出作用域,pB的引用计数减少为1,不为0,因此堆上的pb所指空间没有被释放;同理pA

}

所以在使用基于引用计数的智能指针时,要特别小心循环引用带来的内存泄漏,循环引用不只是两方的情况,只要引用链成环都会出现问题。当然循环引用本身就说明设计上可能存在一些问题。

这就是使用强引用所带来的问题。使用weak_ptr解决

weak_ptr从字面意思上可以看出是一个弱指针,不是说明这个指针的能力比较弱,而是说他对他所引用的对象的所有权比较弱。说得更直接一点儿就是他并不拥有所引用对象的所有权,而且他还不能直接使用他所引用的对象。

在stl中,weak_ptr是和shared_ptr配合使用的,在实现shared_ptr的时候也就考虑了weak_ptr的因素。weak_ptr是shared_ptr的观察者,它不会干扰shared_ptr所共享对象的所有权,当一个weak_ptr所观察的shared_ptr要释放它的资源时,它会把相关的weak_ptr的指针设置为空,防止weak_ptr持有悬空的指针。

weak_ptr并不拥有资源的所有权,所以不能直接使用资源。可以从一个weak_ptr构造一个shared_ptr以取得共享资源的所有权。

void Function()

{

    shared_ptr<int> sp(new Obj());

    assert(sp.use_count() == 1);

    weak_ptr<int> wp(sp); //从shared_ptr创建weak_ptr

    assert(wp.use_count() == 1);

    if (!wp.expired())//判断weak_ptr观察的对象是否失效

    {

         shared_ptr<int> sp2 = wp.lock();//获得一个shared_ptr

         *sp2 = 100;

         assert(wp.use_count() == 2);

    }

    assert(wp.use_count() == 1);

    return 0;

}

weak_ptr并没有重载-> 和 * 操作符,所以我们不能通过他来直接使用资源,我们可以通过lock来获得一个shared_ptr对象来对资源进行使用。如果引用的资源已经释放,lock()函数将返回一个存储空指针的shared_ptr。expired函数用来判断资源是否失效。

使用weak_ptr并不会增加资源的引用计数。所以对资源的引用是弱引用,利用这个特性可以解决前面所说的循环依赖问题。

class Parent {

public:

    weak_ptr<Child> child;

};

class Child {

public:

    weak_ptr<Parent> parent;

};

void Function(){

    shared_ptr<Parent> pA(new Parent);

    shared_ptr<Child> pB(new Child);

    pA->child = pB;

    pB->parent = pA;

}

这个时候第三和第四条语句的执行并没有增加引用计数,从而在函数执行完成只有能自动释放内存。
    从上面的分析可以看出,weak_ptr是一种辅助shared_ptr的一种智能指针,一般不单独使用,而是结合shared_ptr一起使用。

总结:
1. 尽量使用unique_ptr而不要使用auto_ptr
2. 一般来说shared_ptr能够满足我们大部分的需求
3. weak_ptr可以避免递归的依赖关系

时间: 2024-10-29 19:06:51

四种智能指针:auto_ptr,unique_ptr,shared_ptr,weak_ptr的相关文章

C++ Primer 学习笔记_56_STL剖析(十一)(原boost库):详解智能指针(unique_ptr(原scoped_ptr) 、shared_ptr 、weak_ptr源码分析)

注意:现在boot库已经归入STL库,用法基本上还和boost类似 在C++11中,引入了智能指针.主要有:unique_ptr, shared_ptr, weak_ptr. 这3种指针组件就是采用了boost里的智能指针方案.很多有用过boost智能指针的朋友,很容易地就能发现它们之间的关间: std boost 功能说明 unique_ptr scoped_ptr 独占指针对象,并保证指针所指对象生命周期与其一致 shared_ptr shared_ptr 可共享指针对象,可以赋值给shar

【转】C++面试题(四)——智能指针的原理和实现

C++面试题(四)——智能指针的原理和实现 tanglu2004 http://blog.csdn.net/worldwindjp/   C++面试题(一).(二)和(三)都搞定的话,恭喜你来到这里,这基本就是c++面试题的最后一波了. 1,你知道智能指针吗?智能指针的原理.     2,常用的智能指针.     3,智能指针的实现. 1答案:智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针.智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放, 2,

智能指针auto_ptr详解

概述:C++中有很多种智能指针,auto_ptr就是其中的一种,该智能指针主要是为了解决"因程序异常退出发生的内存泄漏"这类问题的. 我们先来看下面的问题代码 #include<iostream> #include<memory> #include<exception> using namespace std; //一般指针的处理方式 template<typename T> class OldClass { public: OldCla

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

【C++智能指针 auto_ptr】

<More Effective C++>ITEM M9中提到了auto_ptr,说是当异常产生的时候,怎么释放为对象分配的堆内存,避免重复编写内存释放语句. PS:这里书里面提到函数退出问题,函数退出会清理栈内存,不管是怎么正常退出还是异常退出(仅有一种例外就是当你调用 longjmp 时.Longjmp 的这个缺点是 C++率先支持异常处理的主要原因).建立在此基础上我们才把对指针的删除操作封装到一个栈对象里面.这样函数退出(异常或是正常)就会调用对象的析构函数,达到我们自动清理所封装指针指

C++智能指针--auto_ptr指针

auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放.即使发生异常,通过异常的栈展开过程也能将动态内存释放.auto_ptr不支持new数组. auto_ptr的出现,主要是为了解决"有异常抛出时发生内存泄漏"的问题.如下的简单代码是这类问题的一个简单示

C++ 智能指针auto_ptr详解

1. auto_ptr 的设计动机: 函数操作经常依照下列模式进行: 获取一些资源 执行一些动作 释放所获取的资源 那么面对这些资源的释放问题就会出现下面的两种情况: 一开始获得的资源被绑定于局部对象,那么当函数退出的时候,这些局部对象的析构函数被自动的调用,从而自动释放掉这些资源; 一开始获得的资源是通过某种显示手段获取,而且并没有绑定在任何对象身上,那么必须以显式的方式释放.这种情况常常发生在指针身上; 例子: 1 void f() 2 { 3 ClassA* ptr = new Class

C++中的智能指针(auto_ptr)

实际上auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是完全完美的. 本文从下面的8个方面来总结auto_ptr使用的大部分内容. 1. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个这样拥有者(auto_ptr).当auto_ptr对象生命

C++智能指针 auto_ptr

C++智能指针 auto_ptr auto_ptr 是一个轻量级的智能指针, 定义于 memory (非memory.h)中, 命名空间为 std. auto_ptr 适合用来管理生命周期比较短或者不会被远距离传递的动态对象, 最好是局限于某个函数内部或者是某个类的内部. 使用方法: std::auto_ptr<int> pt(new int(10)); pt.reset(new int(11)); 成员函数 3个重要的函数: (1) get 获得内部对象的指针, 由于已经重载了()方法, 因