智能指针std::auto_ptr的用法【转】
http://www.cppblog.com/AutomateProgram/articles/66980.html
原文地址:http://www.oolec.com/smart_pointer_auto_ptr_usage/
在c++程序中,内存管理中经常隐藏着很深的bug。
虽然我们一般可以采用vector,string,map等容器自动管理内存,
但涉及多态,继承的时候也不可避免的要手动管理,c++标准库中提供的auto_ptr能一定程度上帮助我们。
auto_ptr用法:
1.需要包含头文件
2.Constructor:explicit auto_ptr(X* p = 0) throw();
将指针p交给auto_ptr对象托管
3.Copy constructor:
auto_ptr(const auto_ptr&) throw();
template auto_ptr(const auto_ptr& a) throw();
指针的托管权会发生转移
4.Destructor: ~auto_ptr();
释放指针p指向的空间
5.提供了两个成员函数
X* get() const throw();//返回保存的指针,对象中仍保留指针
X* release() const throw();//返回保存的指针,对象中不保留指针
auto_ptr实现关键点
1.利用特点”栈上对象在离开作用范围时会自动析构”
2.对于动态分配的内存,其作用范围是程序员手动控制的,这给程序员带来了方便但也不可避免疏忽造成的内存泄漏,毕竟只有编译器是最可靠的。
3.auto_ptr通过在栈上构建一个对象a,对象a中wrap了动态分配内存的指针p,所有对指针p的操作都转为对对象a的操作。而在a的析构函数中会自动释放p的空间,而该析构函数是编译器自动调用的,无需程序员操心。
多说无益,看一个最实用的例子:
#include <iostream> #include <memory> using namespace std; class TC { public: TC(){ cout<<"TC()"<<endl; } ~TC(){ cout<<"~~TC()"<<endl;} }; void foo(bool isThrow) { auto_ptr<TC> pTC(new TC); //方法2 // TC *pTC=new TC; //方法1 try { if (isThrow) throw "haha"; } catch (const char* e) { // delete pTC; //方法1 throw; } // delete pTC; //方法1 } int main() try { foo(true); } catch () { cout<<"caught"<<endl; }
分析:
1.如果采用方案1,那么必须考虑到函数在因throw异常的时候释放所分配的内存。
这样造成的结果是在每个分支处都要很小心的手动 delete pTC;
2.如果采用方案2,那就无需操心何时释放内存,不管foo()因何原因退出,
栈上对象pTC的析构函数都将调用,因此托管在之中的指针所指的内存必然安全释放。
注意:
至此,智能指针的优点已经很明了了。
但是要注意使用中的一个陷阱,那就是指针的托管权是会转移的。
例如在上例中,如果
auto_ptr pTC(new TC);
auto_ptr pTC1=pTC;
那么,pTC1将拥有该指针,而pTC没有了,如果再用pTC去引用,必然导致内存错误。
要避免这个问题,可以考虑使用采用了引用计数的智能指针,例如boost::shared_ptr等
个人观点
1.
vc++库中的智能指针auto_ptr本不像都像前面介绍的那样
auto_ptr pTC(new TC);
auto_ptr pTC1=pTC;
其中pTC指针并没有被托管,其地址还是指向new TC 的。但是并没有出现同一个指针释放两次的问题。
2.VC中的 auto_ptr是一个对象,和内置指针是不一样的,它没有支持测试智能指针NULL的功能。
auto_ptr<TestC> p;
if(p == NULL); 并没有办法通过编译。
3.并不支持将智能指针转化为内置指针,如:
void print(TestC* p)
{
//...
}
auto_ptr<TestC> p(new TestC);
print(p);没有办法通过编译
解决的办法是重载operator T*();
4.内置指针在c++中一个重要的作用是用来实现多态,但是vc++智能指针并不支持.
实现的方法是
template<class T>
template <class U>
MyAuto_ptr(MyAuto_ptr<U>& rhs);
可以参考:《More Effective c++ 》条款28 P158