智能指针
智能指针其实挺容易的。
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