Stl 中 auto_ptr只是众多可能的智能指针之一,auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理。
这里是一个简单的代码示例,如果没有auto_ptr,
2 {
3
4 while (data) // 如果还有数据
5 {
6 ALA *pa = readALAData(data); // 取出下一个数据
7 pa->DealProcessAdoption(data); // 处理
8
9 delete pa; // 释放资源
10 }
11 return;
12}
如果在DealProcessAdoption有一个exception,会发生什么事情,因为ProcessAdoption不能捕获他,所以这段代码很危险,所以DealProcessAdoption后面的代码可能会跳过,造成内存泄露。
如果利用try catch去捕获他,会搞得代码很乱,又缺少美观性。
所以Stl提供了一个智能指针来解决这个问题,我们可以先模拟实现一个智能指针的类实现。
2 template < typename Type >
3 class auto_ptr
4 {
5public:
6 auto_ptr(T *p =NULL) :Ptr(p)
7 { }
8 ~auto_ptr()
9 {
10 delete Ptr;
11 }
12private:
13 Type *Ptr;
14} ;
15
16
17 void ProcessAdoption(istream & data)
18 {
19
20 while (data) // 如果还有数据
21 {
22 auto_ptr<ALA> pa(readALADara(data));
23 pa->DealProcessAdoption(data);
24 }
25 return;
26}
这个版本和原先版本的差异只有二处,
第一pa是一智能指针的对象,不是ALA*
第二不用自己去释放delete
然后我看到Effective STL的条款
8:永不建立auto_ptr的容器
关于此可以看的Effective STL的条款8
因为auto_ptr并不是完美无缺的,它的确很方便,但也有缺陷,在使用时要注意避免。首先,不要将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果
auto_ptr的另一个缺陷是将数组作为auto_ptr的参数: auto_ptr<char> pstr (new char[12] ); //数组;为定义
然后释放资源的时候不知道到底是利用delete pstr,还是 delete[] pstr;
然后收集了关于auto_ptr的几种注意事项:
1、auto_ptr不能共享所有权。
2、auto_ptr不能指向数组
3、auto_ptr不能作为容器的成员。
4、不能通过赋值操作来初始化auto_ptr
std::auto_ptr<int> p(new int(42)); //OK
std::auto_ptr<int> p = new int(42); //ERROR
这是因为auto_ptr 的构造函数被定义为了explicit
5、不要把auto_ptr放入容器
然后笔者从而推荐的是boost的shared_ptr,然后看完shared_ptr关于智能指针的介绍与例子。
5种针对auto_ptr不足的指针如下:需要详细了解可以去查看相当文档,与测试新代码。
scoped_ptr | <boost/scoped_ptr.hpp> | 简单的单一对象的唯一所有权。不可拷贝。 |
scoped_array | <boost/scoped_array.hpp> | 简单的数组的唯一所有权。不可拷贝。 |
shared_ptr | <boost/shared_ptr.hpp> | 在多个指针间共享的对象所有权。 |
shared_array | <boost/shared_array.hpp> | 在多个指针间共享的数组所有权。 |
weak_ptr | <boost/weak_ptr.hpp> | 一个属于 shared_ptr 的对象的无所有权的观察者。 |
intrusive_ptr | <boost/intrusive_ptr.hpp> | 带有一个侵入式引用计数的对象的共享所有权。 |
1. shared_ptr是Boost库所提供的一个智能指针的实现,shared_ptr就是为了解决auto_ptr在对象所有权上的局限性(auto_ptr是独占的),在使用引用计数的机制上提供了可以共享所有权的智能指针.
2. shared_ptr比auto_ptr更安全
3. shared_ptr是可以拷贝和赋值的,拷贝行为也是等价的,并且可以被比较,这意味这它可被放入标准库的一般容器(vector,list)和关联容器中(map)。
关于shared_ptr的使用其实和auto_ptr差不多,只是实现上有差别,关于shared_ptr的定义就不贴代码了,以为内开源,可以网上找
1、shared_ptr<T> p(new Y);
shared_ptr是boost.smart_ptr库中最具价值、最有份量的组成部分。它与scoped_ptr一样包装了new操作符在堆上分配动态对象,但它实现的是引用计数(reference-count)型智能指针,可以被自由地拷贝和赋值,在任意的地方共享它。当引用计数值为0,也即没有代码使用它时它会自动删除被分配资源的对象。
shared_ptr可以安全地放到标准容器中,并弥补了auto_ptr因为转移语义而不能把指针STL容器元素的缺陷。C++历史上出现过很多引用计数型的智能指针,但没有一个比得上boost::shared_ptr的,过去,现在,将来它都是最好的。
类摘要:
- template<class T> class shared_ptr
- {
- private:
- // Borland 5.5.1 specific workaround
- typedef shared_ptr<T> this_type;
- public:
- typedef T element_type;
- typedef T value_type;
- typedef T * pointer;
- typedef typename boost::detail::shared_ptr_traits<T>::reference reference;
- shared_ptr();
- template<class Y>
- explicit shared_ptr( Y * p );
- template<class Y, class D> shared_ptr(Y * p, D d);
- template<class Y, class D, class A> shared_ptr( Y * p, D d, A a );
- template<class Y>
- explicit shared_ptr(weak_ptr<Y> const & r);
- template<class Y>
- shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag );
- template<class Y>
- shared_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() );
- shared_ptr( shared_ptr<Y> const & r );
- template< class Y >
- shared_ptr( shared_ptr<Y> const & r, T * p );
- template<class Y>
- shared_ptr(shared_ptr<Y> const & r, boost::detail::static_cast_tag);
- template<class Y>
- shared_ptr(shared_ptr<Y> const & r, boost::detail::const_cast_tag);
- template<class Y>
- shared_ptr(shared_ptr<Y> const & r, boost::detail::dynamic_cast_tag);
- template<class Y>
- shared_ptr(shared_ptr<Y> const & r, boost::detail::polymorphic_cast_tag);
- template<class Y>
- explicit shared_ptr(std::auto_ptr<Y> & r);
- template<class Ap>
- explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type = 0 );
- shared_ptr & operator=( shared_ptr const & r ) // never throws
- template<class Y>
- shared_ptr & operator=(shared_ptr<Y> const & r) //never throw
- template<class Y>
- shared_ptr & operator=( std::auto_ptr<Y> & r );
- template<class Ap>
- typename boost::detail::sp_enable_if_auto_ptr< Ap, shared_ptr & >::type operator=( Ap r );
- shared_ptr( shared_ptr && r );
- template<class Y>
- shared_ptr( shared_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
- shared_ptr( shared_ptr<Y> && r );
- shared_ptr & operator=( shared_ptr && r ); // never throws
- template<class Y>
- shared_ptr & operator=( shared_ptr<Y> && r ) // never throws
- void reset() ;// never throws in 1.30+
- template<class Y> void reset(Y * p) // Y must be complete
- template<class Y, class D> void reset( Y * p, D d );
- template<class Y, class D, class A> void reset( Y * p, D d, A a );
- template<class Y> void reset( shared_ptr<Y> const & r, T * p );
- reference 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
- void swap(shared_ptr<T> & other);// never throws
- template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const;
- void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti );
- bool _internal_equiv( shared_ptr const & r ) const;
- private:
- template<class Y> friend class shared_ptr;
- template<class Y> friend class weak_ptr;
- T * px; // contained pointer
- boost::detail::shared_count pn; // reference counter
- }; // shared_ptr
template<class T> class shared_ptr
{
private:
// Borland 5.5.1 specific workaround
typedef shared_ptr<T> this_type;
public:
typedef T element_type;
typedef T value_type;
typedef T * pointer;
typedef typename boost::detail::shared_ptr_traits<T>::reference reference;
shared_ptr();
template<class Y>
explicit shared_ptr( Y * p );
template<class Y, class D> shared_ptr(Y * p, D d);
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a );
template<class Y>
explicit shared_ptr(weak_ptr<Y> const & r);
template<class Y>
shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag );
template<class Y>
shared_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() );
shared_ptr( shared_ptr<Y> const & r );
template< class Y >
shared_ptr( shared_ptr<Y> const & r, T * p );
template<class Y>
shared_ptr(shared_ptr<Y> const & r, boost::detail::static_cast_tag);
template<class Y>
shared_ptr(shared_ptr<Y> const & r, boost::detail::const_cast_tag);
template<class Y>
shared_ptr(shared_ptr<Y> const & r, boost::detail::dynamic_cast_tag);
template<class Y>
shared_ptr(shared_ptr<Y> const & r, boost::detail::polymorphic_cast_tag);
template<class Y>
explicit shared_ptr(std::auto_ptr<Y> & r);
template<class Ap>
explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type = 0 );
shared_ptr & operator=( shared_ptr const & r ) // never throws
template<class Y>
shared_ptr & operator=(shared_ptr<Y> const & r) //never throw
template<class Y>
shared_ptr & operator=( std::auto_ptr<Y> & r );
template<class Ap>
typename boost::detail::sp_enable_if_auto_ptr< Ap, shared_ptr & >::type operator=( Ap r );
shared_ptr( shared_ptr && r );
template<class Y>
shared_ptr( shared_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
shared_ptr( shared_ptr<Y> && r );
shared_ptr & operator=( shared_ptr && r ); // never throws
template<class Y>
shared_ptr & operator=( shared_ptr<Y> && r ) // never throws
void reset() ;// never throws in 1.30+
template<class Y> void reset(Y * p) // Y must be complete
template<class Y, class D> void reset( Y * p, D d );
template<class Y, class D, class A> void reset( Y * p, D d, A a );
template<class Y> void reset( shared_ptr<Y> const & r, T * p );
reference 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
void swap(shared_ptr<T> & other);// never throws
template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const;
void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti );
bool _internal_equiv( shared_ptr const & r ) const;
private:
template<class Y> friend class shared_ptr;
template<class Y> friend class weak_ptr;
T * px; // contained pointer
boost::detail::shared_count pn; // reference counter
}; // shared_ptr
shared_ptr重载了*和->操作符以模仿原始指针的行为,同时提供隐式bool类型转换判断指针是否有效。get()可以得到原始指针,没有提供指针算术操作。它可以正常地拷贝,赋值,也可以进行shared_ptr之间的比较,是最智能的智能指针。
shared_ptr有多种形式的构造函数,应用于各种可能的情形:
1,无参的shared_ptr()创建一个持有空指针的shared_ptr
2,shared_ptr(Y *p)获得指向类型T的指针p的管理权,同时引用计数置为1。这个构造函数要求T类型必须能够转换成Y类型
3,shared_ptr(shared_ptr const &r)从另外一个shared_ptr获得指针的管理权,同时引用计数为1,结果是两个shared_ptr共享一个指针的管理权。
4,shared_ptr(std::auto<Y> &r)从一个auto_ptr获得指针的管理权,引用计数置为1,同时auto_ptr自动失去管理权。
5,operator=赋值操作符可以从另外一个shared_ptr或auto_ptr获得指针的管理权,其行为同构造函数
6,shared_ptr(Y *p,D d)行为类似shared_ptr(Y *p),但使用参数d指定了析构时的定制删除器,而不是简单的delete。
shared_ptr的reset()函数是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则类似相同形式的构造函数,原指针引用计数减1的同时改为管理另外一个指针。
shared_ptr有两个函数来检查引用计数,unique()在shared_ptr是指针的唯一所有者时返回true(这时的行为类似auto_ptr或scoped_ptr),use_count()返回当前指针的引用计数。不过小心了,use_count()仅仅用于测试或者调试,它不提供高效的操作,而且有时可能是不可用的。但是unique()是可靠的,任何时候都可以用,而且比use_count() == 1速度更快。
shared_ptr支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get() == b.get() 。还可以使用operator<比较大小,同样基于内部保存的指针,但不提供除它以外的比较符,这使得shared_ptr可以被应用于标准关联容器(set和map):
typedef shared_ptr<string> sp_t;
map<sp_t,int > m; //标准映射容器
sp_t sp(new string("one"));
m[sp] = 111;
在编写基于虚函数的多态代码时指针的类型转换很有用,比如把一个基类指针转换成一个继承类指针或者反过来(继承类指针转换成基类指针)。但对于shared_ptr不能使用诸如static_cast<T *>(p.get())的形式。这将导致转型后的指针无法再被shared_ptr正确管理。为了支持这种用法,shared_ptr提供了类似的转型函数static_pointer_cast<T>() ,const_pointer_cast<T>, dynamic_pointer_cast<T>类似,但它返回的是转型后的shared_ptr。
例如,下面的代码使用dynamic_pointer_cast把一个shared_ptr<std::exception>向下转型为一个shared_ptr<bad_exception>,然后又用static_pointer_cast重置转为shared_ptr<std::exception>;
shared_ptr<std::exception> sp1(new bad_exception("error"));
shared_ptr<bad_exception> sp2 = dynamic_pointer_cast<bad_exception>(sp1);
shared_ptr<std::exception> sp3 = static_pointer_cast<std::exception>(sp2);
assert(sp3 == sp1);
shared_ptr还支持流输出操作符operator<<,输出内部的指针值,方便调试。
使用示例:
- #include <iostream>
- #include <boost/smart_ptr.hpp>
- using namespace boost;
- using namespace std;
- class shared //define a custom class
- {
- public:
- shared(shared_ptr<int> p):_p(p){}
- void print()
- {
- cout << "count: " << _p.use_count()
- << " v= " << *_p << endl;
- }
- private:
- shared_ptr<int> _p;
- };
- void print_func(shared_ptr<int> p)
- {
- cout << "count: " << p.use_count()
- << " v= " << *p << endl;
- }
- int main()
- {
- /*
- /*example1
- shared_ptr<int> sp(new int(10));//a smart_ptr pointed to int
- assert(sp.unique()); //shared_ptr is the only owner of pointer
- shared_ptr<int> sp2 = sp; //the second shared_ptr,copy construct
- assert(sp == sp2 && sp.use_count() == 2);
- //Two shared_ptr equal, pointing in the same object, reference counting is 2
- *sp2 = 100; //now print *sp2
- assert(*sp == 100);
- sp.reset();//
- assert(!sp);//sp now is empty
- cout << "no problem." << endl;
- */
- /*example2*/
- shared_ptr<int> p(new int(100));
- shared s1(p),s2(p);//custom shared class object
- s1.print(); //3
- s2.print();//3
- *p = 20; //modify the value of the object which p point to
- print_func(p);//display use_count 4
- s1.print();//3
- }
#include <iostream>
#include <boost/smart_ptr.hpp>
using namespace boost;
using namespace std;
class shared //define a custom class
{
public:
shared(shared_ptr<int> p):_p(p){}
void print()
{
cout << "count: " << _p.use_count()
<< " v= " << *_p << endl;
}
private:
shared_ptr<int> _p;
};
void print_func(shared_ptr<int> p)
{
cout << "count: " << p.use_count()
<< " v= " << *p << endl;
}
int main()
{
/*
/*example1
shared_ptr<int> sp(new int(10));//a smart_ptr pointed to int
assert(sp.unique()); //shared_ptr is the only owner of pointer
shared_ptr<int> sp2 = sp; //the second shared_ptr,copy construct
assert(sp == sp2 && sp.use_count() == 2);
//Two shared_ptr equal, pointing in the same object, reference counting is 2
*sp2 = 100; //now print *sp2
assert(*sp == 100);
sp.reset();//
assert(!sp);//sp now is empty
cout << "no problem." << endl;
*/
/*example2*/
shared_ptr<int> p(new int(100));
shared s1(p),s2(p);//custom shared class object
s1.print(); //3
s2.print();//3
*p = 20; //modify the value of the object which p point to
print_func(p);//display use_count 4
s1.print();//3
}
运行结果:
count: 3 v= 100
count: 3 v= 100
count: 4 v= 20
count: 3 v= 20
注意,我们没有使用引用方式传递参数,而是直接拷贝,就像是使用一个原始指针,shared_ptr支持这样的用法。
在声明了share_ptr和两个shared类实例后,指针被它们所共享,因此引用计数为3。print_fun()函数内部拷贝了一个shared_ptr对象,因此引用计数再增加1,退出的时候拷贝自动析构,引用计数又恢复到了3
boost::scoped_ptr虽然简单易用,但它不能共享所有权的特性却大大限制了其使用范围,而boost::shared_ptr可以解决这一局限。顾名思义,boost::shared_ptr是可以共享所有权的智能指针,首先让我们通过一个例子看看它的基本用法:
#include<string>
#include <iostream>
#include <boost/shared_ptr.hpp>
class implementation
{
public:
~implementation() { std::cout <<"destroying implementation\n"; }
void do_something() { std::cout << "did something\n"; }
};
void test()
{
boost::shared_ptr<implementation> sp1(new implementation());
std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n";
boost::shared_ptr<implementation> sp2 = sp1;
std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n";
sp1.reset();
std::cout<<"After Reset sp1. The Sample now has "<<sp2.use_count()<<" references\n";
sp2.reset();
std::cout<<"After Reset sp2.\n";
}
void main()
{
test();
}
该程序的输出结果如下:
The Sample now has 1 references
The Sample now has 2 references
After Reset sp1. The Sample now has 1 references
destroying implementation
After Reset sp2.
可以看到,boost::shared_ptr指针sp1和sp2同时拥有了implementation对象的访问权限,且当sp1和sp2都释放对该对象的所有权时,其所管理的的对象的内存才被自动释放。在共享对象的访问权限同时,也实现了其内存的自动管理。
boost::shared_ptr的内存管理机制:
boost::shared_ptr的管理机制其实并不复杂,就是对所管理的对象进行了引用计数,当新增一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数加一;减少一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数减一,如果该对象的引用计数为0的时候,说明没有任何指针对其管理,才调用delete释放其所占的内存。
上面的那个例子可以的图示如下:
-
sp1对implementation对象进行管理,其引用计数为1
-
增加sp2对implementation对象进行管理,其引用计数增加为2
-
sp1释放对implementation对象进行管理,其引用计数变为1
-
sp2释放对implementation对象进行管理,其引用计数变为0,该对象被自动删除
boost::shared_ptr的特点:
和前面介绍的boost::scoped_ptr相比,boost::shared_ptr可以共享对象的所有权,因此其使用范围基本上没有什么限制(还是有一些需要遵循的使用规则,下文中介绍),自然也可以使用在stl的容器中。另外它还是线程安全的,这点在多线程程序中也非常重要。
boost::shared_ptr的使用规则:
boost::shared_ptr并不是绝对安全,下面几条规则能使我们更加安全的使用boost::shared_ptr:
-
避免对shared_ptr所管理的对象的直接内存管理操作,以免造成该对象的重释放
-
shared_ptr并不能对循环引用的对象内存自动管理(这点是其它各种引用计数管理内存方式的通病)。
-
不要构造一个临时的shared_ptr作为函数的参数。
如下列代码则可能导致内存泄漏:
void test()
{
foo(boost::shared_ptr<implementation>(new implementation()),g());
}
正确的用法为 :
void test()
{
boost::shared_ptr<implementation> sp (new implementation());
foo(sp,g());
}