智能指针其实挺容易的。
1. scoped_ptr<T>
将指针自身的生命周期与对象绑定,“我死之日也是你亡之时”
例如:
#include "boost/smart_ptr.h"
void Sample1_ScopedPtr()
boost::scoped_ptr<CSample>
samplePtr(new CSample);
if (!samplePtr->Query() )
// just some function...
return;
samplePtr->Use();
当我们使用例外的时候处理指针是特别烦人的事情(容易忘记销毁它)。使用scoped_ptr 指针就能够在函数结束的时候自动销毁它,因为这时scope_ptr也要完蛋了。
2、 shared_ptr
通过引用计数来管理对象的生命,引用计数听过好多遍了--对引用次数作个记录,但要关键要搞清楚的是这个“计数”是放在哪儿的?计数是在直接由对象原始指针创建shared_ptr时在堆上分配的;而通过拷贝构造或赋值得到的shared_ptr的计数则指向此计数了。这注定了两件事:
1.不能有多个shared_ptr直接由原始指针创建而来 2.不能形成循环计数。
再有一个重点是,从其语义上,要对对象的生命周期做出管理。如果语境中,不需要一个指针具有管理对象生命周期的语义,此时再使用shared_ptr有可能会违背以上两点。此时可考虑使用week_ptr
void Sample2_Shared(){
// (A) 创建Csample类的一个实例和一个引用。
boost::shared_ptr<CSample> mySample(new CSample);
printf("The Sample now has %i references\n", mySample.use_count()); // The Sample now has 1 references
// (B) 付第二个指针给它。
boost::shared_ptr<CSample> mySample2 = mySample; // 现在是两个引用指针。
printf("The Sample now has %i references\n", mySample.use_count());
// (C) 设置第一个指针为空。
mySample.reset();
printf("The Sample now has %i references\n", mySample2.use_count()); // 一个引用
// 当mySample2离开作用域的时候,对象只有一个引用的时候自动被删除。
}
一个误用的例子:
class foo {
public:
typedef std::shared_ptr<foo> type_ptr;
//blablabla....
type_ptr what_are_you_want_to_do() {
// 一堆不知道干嘛的代码后
return type_ptr(this);
}
};
int main() {
foo::type_ptr p = foo::type_ptr(new foo());
p->what_are_you_want_to_do();
return 0;
}
此处 return type_ptr(this) 语义不需要对foo对象的生命周期管理,使用shared_ptr是不合理的。
但也确实脑慢了就容易错啊。
3、 使用weak_ptr跳出循环
weak_ptr并不对对象的生命周期进行参与,它的座右铭是“我只看看,不说话”,对象活着就用,不存在就返回空指针。
其原理是,不对引用计数作修改。
4、 Intrusive_ptr——轻量级共享智能指针
shared_ptr比普通指针提供了更完善的功能。有一个小小的代价,那就是一个共享指针比普通指针占用更多的空间,每一个对象都有一个共享指针,这个指针有引用计数器以便于释放。但对于大多数实际情况,这些都是可以忽略不计的。
前面三个指针对对象没啥要求,但intrusive_ptr 则要对象本身已经有了一个对象引用计数器,也是“侵入”的来源。此时因为“计数”在对象内,下面这样就没啥问题了(与shared_ptr相比):
p = new P()
f = boost::intrusive_ptr<P>(p)
g = boost::intrusive_ptr<P>(p)
如果你要使用intrusive_ptr 指向类型T,那么你就需要定义两个函数:intrusive_ptr_add_ref 和intrusive_ptr_release。下面是一个简单的例子解释如何在自己的类中实现:
#include "boost/intrusive_ptr.hpp"
// forward declarations
class CRefCounted;
namespace boost
void intrusive_ptr_add_ref(CRefCounted * p);
void intrusive_ptr_release(CRefCounted * p);
// My Class
class CRefCounted
private:
long references;
friend void ::boost::intrusive_ptr_add_ref(CRefCounted * p);
friend void ::boost::intrusive_ptr_release(CRefCounted * p);
public:
CRefCounted() : references(0) {} // initialize references to 0
// class specific addref/release implementation
// the two function overloads must be in the boost namespace on most compilers:
namespace boost
inline void intrusive_ptr_add_ref(CRefCounted * p)
// increment reference count of object *p
++(p->references);
inline void intrusive_ptr_release(CRefCounted * p)
// decrement reference count, and delete object when reference count reaches 0
if (--(p->references) == 0)
delete p;
} // namespace boost