[原] 智能指针 对比

发布时间:2014-6-4 12:09
分类名称:Boost


auto_ptr

scoped_ptr

shared_ptr

无引用计数

无引用计数

有引用计数

不同auto_ptr引用一个指针,导致多次析构而崩溃

 

int* p = new int(0);

auto_ptr<int> ap1(p);

auto_ptr<int> ap2(p);

 

一个指针被多个auto_ptr引用,导致多次析构,程序崩溃。

同auto_ptr

预防的方式为:

将new 操作直接作为参数传入,等于建立一个临时变量:

scopted_ptr<int> sp(new int(0));

这样,从语言层以后就无法再次引用。

 

由于构造函数explicit关键字的限制,这些智能指针只能在定义的时候初始化,以后不能被再次赋值其它指针,如:

CTest *p = new CTest;

std::auto_ptr<CTest> ap;

ap = p; // 错误,编译器报错

同样也是无法预防,但是在Boost里,有预防此情况的调试机制:

如果定义了宏BOOST_SP_ENABLE_DEBUG_HOOKS,

当出现此种情况时,第二次的引用会弹出一个assert调试框。其代码实现在: libs\smart_ptr\src\sp_debug_hooks.cpp中。调试机制提前预防了多次析构的问题,所以在Debug的状态,打开此机制。此调试机制适应于boost中所有智能指针(smart_ptr)

无法处理动态数组

int* pa = new int[10];

auto_ptr<int> ap(pa);

因为auto_ptr析构删除指针使用的的是delete,而不是delete[],所以这种用法不正确,程序的运行结果未定。

scoped_array可以来处理动态数组。

动态数组最好使用vector代替。

shared_array来处理动态数组。

独占,不共享,所有权转移

因为没有引用计数,所以无法实现多个auto_ptr共享一个指针的目的。所以拷贝和复制操作,需要特殊处理,保证拷贝后,被拷贝的auto_ptr不再有原指针的所有权。(所有权转移

 

使用没有原指针所有权auto_ptr是很危险的,就如同在操作一个空指针一样。如:

int* p = new int(0);

auto_ptr<int> ap1(p);

auto_ptr<int> ap2 = ap1;

cout<<*ap1; //错误,此时ap1只剩一个null指针在手了

 

更加隐蔽的:

void f(auto_ptr<int> ap){cout<<*ap;}

auto_ptr<int> ap1(new int(0));

f(ap1);

cout<<*ap1; //错误,经过f(ap1)函数调用,ap1已经不再拥有任何对象了。

 

独占的特性导致了它的危险性。

独占,不共享,不过无法转移:

不能转移的技术:

将能拷贝和赋值构造函数都声明为私有。

private:

scoped_ptr(scoped_ptr const &);

scoped_ptr & operator= (scoped_ptr const &);

void operator==( scoped_ptr const& ) const;

void operator!=( scoped_ptr const& ) const;

 

此接口保证功能最小,主要起自动释放的作用。

共享,通过引用计数来维护指针

 

由于有引用计数,多个share_ptr可以引用一个指针。使用起来,和实际的指针基本上是一模一样。

不具有值语义(value semantic)

因为具有所有权转移特性

不能被用在STL标准容器中

不具有值语义(value semantic)

因为不支持拷贝,赋值等操作

不能被用在STL标准容器中

就有值语意

可以用在容器中。

辅助函数

get函数,获取原始指针。

release 函数,转移所有权(不释放,只是清零)

reset函数,用来接收所有权,如果接收所有权的auto_ptr如果已经拥有某对象, 必须先释放该对象。

operator bool()

辅助函数

get函数,获取原始指针。

reset函数,用来接收所有权,如果接收所有权的auto_ptr如果已经拥有某对象, 必须先释放该对象。

operator bool()

辅助函数

reset,引用计数减1,停止对指针共享,如果引用计数为零,释放对象

get,获取原始指针

unique,判断引用计数是否为1.

use_count,获取当前引用计数。

operator bool()

make_shared,工厂函数

 

转换辅助函数

static_pointer_cast

dynamic_pointer_cast

const_pointer_cast

 

定制删除器

shared_ptr(Y *p, D d),管理任何资源。

需要注意的地方颇多,稍不注意就会发生错误,建议只做自动释放的功能,不要做为函数参数,或者赋值转移等操作

相对auto_ptr做了防御编程,但没有完全防止,建议只做自动释放的功能。

功能最完善,最像一个正常的指针。需要注意两点:

  1. 防止重复析构,导致资源重复释放
  2. 防止循环引用,导致资源无法释放