看下面情况
string * pstr = new string;
g(); // 如果 g 掷出一个异常,内存溢出
delete pstr; // 如果 g 掷出一个异常,则此行为不能达到的代码行。
那就不能delete pstr了.
try … catch ?
try
{
string * pstr = new string;
g(); // 如果 g 掷出一个异常,内存溢出
delete pstr; // 如果 g 掷出一个异常,则此行为不能达到的代码行。
}
catch(…)
{
// 这个局部空间中没有pstr.
}
于是就有了
auto_ptr
#include <memory> // 注意头文件
#include <string>
using namespace std;
void func()
{
auto_ptr<string> pstr (new string); /* 创建并初始化auto_ptr */
}
1. auto_ptr重载了操作符&,*和->。不要被语法误导,记住pstr是一个对象,不是一个指针。只是它重载了这些操作符后, 使用上相指针一样.
2. 不要将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果
3. 不要将数组作为auto_ptr的参数, 可以理解到在auto_ptr中, 使用delete, 但没有使用delete [].
4. auto_ptr不能作为容器的成员。
5. 不能通过赋值操作来初始化auto_ptr
std::auto_ptr<int> p(new int(42)); // OK
std::auto_ptr<int> p = new int(42); // ERROR
这是因为auto_ptr 的构造函数被定义为了explicit
看这段代码:
#include "stdafx.h"
#include <memory>
#include <iostream>
class CTest
{
private:
int m_nData;
public:
CTest(int nData = 0)
: m_nData(nData)
{
}
~CTest(){}
public:
void Show()
{
std::cout << m_nData << std::endl;
}
};
void FunFirst(std::auto_ptr< CTest > pA)
{
pA->Show();
};
int _tmain(int argc, _TCHAR* argv[])
{
std::auto_ptr< CTest > pA( new CTest(5));
FunFirst( pA );
pA->Show();
return 0;
}
表面上看好像没有问题, 但是看一下
void FunFirst(std::auto_ptr< CTest > pA);
FunFirst( pA ); // 这里调用的时候, 会使用auto_ptr的构造函数
// auto_ptr(auto_ptr<_Ty>& _Right) _THROW0()
// : _Myptr(_Right.release())
// { // construct by assuming pointer from _Right auto_ptr
// }
// 在这个构造函数中, 调用了 auto_ptr::release()
// _Ty *release() _THROW0()
// { // return wrapped pointer and give up ownership
// _Ty *_Tmp = (_Ty *)_Myptr;
// _Myptr = 0; // 这里是关键 _Myptr被清0了.
// return (_Tmp);
// }
那在FunFirst( pA );下面的pA->Show();中, pA中的_Myptr已经被清0了, 再调用Show就会报错.
把void FunFirst(std::auto_ptr< CTest > pA)改为
void FunFirst(const std::auto_ptr< CTest >& pA)即可
以上这段代码就是关于智能指针的实现问题: 如果智能指针的实现是使用引用计数的话, 以上代码将不会报错, 但stl中的auto_ptr是使用拥有权去实现, 拥有权给了别人之后, 就不能再使用了.
再看下面代码
// 示例2: 使用一个auto_ptr
void g()
{
CTest* pt1 = new CTest;
// 现在,我们有了一个分配好的对象
// 将所有权传给了一个auto_ptr对象
auto_ptr<CTest> pt2( pt1 );
// 使用auto_ptr就像我们以前使用简单指针一样
*pt2 = 12; // 就像"*pt1 = 12;"
pt2->SomeFunc(); // 就像"pt1->SomeFunc();"
// 用get()来获得指针的值
assert( pt1 == pt2.get() );
// 用release()来撤销所有权
CTest* pt3 = pt2.release();
// 自己删除这个对象,因为现在
// 没有任何auto_ptr拥有这个对象
delete pt3;
// pt2不再拥有任何指针,所以不要
// 试图删除它...ok,不要重复删除
}
// 最后,我们可以使用auto_ptr的reset()函数来重置auto_ptr使之拥有另一个对象。
// 如果这个auto_ptr已经拥有了一个对象,那么,它会先删除已经拥有的对象,
// 因此调用reset()就如同销毁这个auto_ptr,然后新建一个并拥有一个新对象:
// 示例3: 使用reset()
//
void h()
{
auto_ptr<CTest> pt( new CTest(1) );
pt.reset( new T(2) );
// 删除由"new T(1)"分配出来的第一个T
// 最后,pt出了作用域,
// 第二个T也被删除了
}
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);
要了解更多关于auto_ptr的信息,可以查看more effective c++ 的p158页条款28
要了解shared_ptr 类模板信息,可以查看boost 1.37.0中文文档,而且支持数组的shared_array 类模板
总之就是使用智能指针时, 需要注意其实现, 否则错误可能会很难找的.
// C++ 的文档网站
http://www.cplusplus.com/
引用
http://www.chinaitpower.com/A/2003-06-17/47697.html