shared_ptr是一种
智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的
引用计数(reference counting)。
作用
auto_ptr由于它的破坏性复制语义,无法满足
标准容器对元素的要求,因而不能放在标准容器中;如果我们希望当容器析构时能自动把它容纳的指针元素所指的对象删除时,通常采用一些间接的方式来实现,显得比较繁琐。
boost库中提供了一种新型的
智能指针shared_ptr,它解决了在多个指针间共享对象所有权的问题,同时也满足容器对元素的要求,因而可以安全地放入容器中。
发展历史
shared_ptr最初实现于
Boost库中,后来被C++标准委员会收录于
TR1技术报告中,成为C++11标准的一部分。
概要
namespace boost {
class bad_
weak_ptr: public std::exception;
template class weak_ptr;
template class shared_ptr {
public:
typedef T element_type;
shared_ptr(); // never throws
template explicit shared_ptr(Y * p);
template shared_ptr(Y * p, D d);
template shared_ptr(Y * p, D d, A a);
~shared_ptr(); // never throws
shared_ptr(shared_ptr const & r); // never throws
template shared_ptr(shared_ptr const & r); // never throws
template shared_ptr(shared_ptr const & r, T * p); // never throws
template
explicit shared_ptr(weak_ptr const & r);template
explicit shared_ptr(std::auto_ptr & r);shared_ptr & operator=(shared_ptr const & r); // never throws
template shared_ptr & operator=(shared_ptr const & r); // never throws
template shared_ptr & operator=(std::auto_ptr & r);
void reset(); // never throws
template void reset(Y * p);
template void reset(Y * p, D d);
template void reset(Y * p, D d, A a);
template void reset(shared_ptr const & r, T * p); // never throws
T & operator*() const; // never throws
T * operator->() const; // never throws
T * get() const; // never throws
bool unique() const; // never throws
long use_count() const; // never throws
operator unspecified-bool-type() const; // never throws
void swap(shared_ptr & b); // never throws
};
template
bool operator==(shared_ptr const & a, shared_ptr const & b); // never throws
template
bool operator!=(shared_ptr const & a, shared_ptr const & b); // never throws
template
bool operator<(shared_ptr const & a, shared_ptr const & b); // never throws
template void swap(shared_ptr & a, shared_ptr & b); // never throws
template T * get_pointer(shared_ptr const & p); // never throws
template
shared_ptr static_pointer_cast(shared_ptr const & r); // never throws
template
shared_ptr const_pointer_cast(shared_ptr const & r); // never throws
template
shared_ptr dynamic_pointer_cast(shared_ptr const & r); // never throws
template
std::basic_ostream & operator<<(std::basic_ostream & os, shared_ptr const & p);
template
D * get_deleter(shared_ptr const & p);
}
用法
删除共享对象
使用shared_ptr解决的主要问题是知道删除一个被多个客户共享的资源的正确时机。下面是一个简单易懂的例子,有两个类 A和 B, 它们共享一个int实例。使用
boost类 A和 B都保存了一个 shared_ptr
. 在创建 A和 B的实例时,shared_ptr temp被传送到它们的构造函数。这意味着共有三个 shared_ptr:a, b, 和 temp,它们都引向同一个int实例。如果我们用指针来实现对一个的共享,A和 B必须能够在某个时间指出这个int要被删除。在这个例子中,直到main的结束,引用计数为3,当所有 shared_ptr离开了作用域,计数将达到0,而最后一个智能指针将负责删除共享的 int.标准容器
把对象直接存入容器中有时会有些麻烦。以值的方式保存对象意味着使用者将获得容器中的元素的拷贝,对于那些复制是一种昂贵的操作的类型来说可能会有性能的问题。此外,有些容器,特别是 std::
vector, 当你加入元素时可能会复制所有元素,这更加重了性能的问题。最后,传值的语义意味着没有多态的行为。如果你需要在容器中存放多态的对象而且你不想切割它们,你必须用指针。如果你用裸指针,维护元素的完整性会非常复杂。从容器中删除元素时,你必须知道容器的使用者是否还在引用那些要删除的元素,不用担心多个使用者使用同一个元素。这些问题都可以用shared_ptr来解决。
下面是如何把共享指针存入标准库容器的例子。
这里有两个类, A和 B, 各有一个虚拟
成员函数 sing. B从 A公有继承而来,并且如你所见,工厂函数 createA返回一个
动态分配的B的实例,包装在shared_ptr
里。在 main里, 一个包含shared_ptr的 std::vector被放入10个元素,最后对每个元素调用sing。如果我们用裸指针作为元素,那些对象需要被手工删除。而在这个例子里,删除是自动的,因为在vector的生存期中,每个shared_ptr的引用计数都保持为1;当 vector被销毁,所有引用
计数器都将变为零,所有对象都被删除。有趣的是,即使 A的
析构函数没有声明为
virtual, shared_ptr也会正确调用 B的析构函数!