C++标准程序库提供的auto_ptr是一种智能型指针,帮助程序员防止“被异常抛出时发生资源泄漏”。注意我说的是“一种”智能型指针,现实生活中还有其余许多有用的智能型指针,auto_ptr只是针对某个特定问题而设计的,对于其余问题,auto-ptr无能为力。ios
1、auto_ptr的设计动机:
函数的操做常常须要依如下模式进行:
一、获取一些资源。
二、执行一些操做。
三、释放所得到的资源。
假如函数一开始得到的资源被绑定在局部对象身上,当函数退出时,他们的析构函数被调用,从而自动释放这些资源。可是若是函数一开始得到的资源是以显式手法(好比说:new)得到,那就必须以显示手法(好比说:delete)释放。可是有时候会忘记delete或者异常一旦发生,函数马上退出,根本执行不到函数尾端的delete语句,这就可能形成内存泄漏。固然你能够在函数中实现捕捉全部异常。但会使得函数变得十分复杂且容易出错。
若是使用智能型指针能保证在任何一种状况下,只要本身被摧毁,就必定连带释放其所指的资源(由于智能型指针原本就是局部变量,因此不管是正常退出,仍是异常退出,都能保证该指针被销毁从而释放资源)。程序员
注意点:
一、auto_ptr是这样一种指针:他是“他所指向的对象”的拥有者。因此,当身为对象拥有者的auto_ptr被摧毁时,该对象也将遭到摧毁。auto_ptr要求一个对象只能有一个拥有者。再也不须要delete,也再也不须要catch。
二、auto_ptr拥有权是能够转移的:函数
std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2(ptr1); 或者 std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2; ptr2 = ptr1;
在第一个语句中,ptr1拥有了那个new出来的对象。在 第二个语句中,拥有权由ptr1转交给ptr2。此后ptr2即拥有了那个new出来的对象,而ptr1不在拥有他。这样,对象就只会被delete一次(在ptr2被摧毁时)。
若是ptr2在转交拥有权以前拥有另外一个对象,则转交操做执行以前会先调用delete,将ptr2所拥有的对象先摧毁。spa
std::auto_ptr<ClassA> ptr1(new ClassA); std::auto_ptr<ClassA> ptr2(new ClassA); ptr2 = ptr1; //ptr2以前拥有的对象被销毁,ptr1将第一个new出来的对象的拥有权转交给ptr2,ptr1为NULL。
特殊用法:某个函数能够利用auto_ptr将拥有权转交给另外一个函数。这种状况可能出如今两种状况:
a、auto_ptr被以传值的方式被看成一个参数传递给某个函数。此时被调用函数的参数就得到了这个auto_ptr的拥有权。设计
void sink(std::auto_ptr<ClassA>);
b、当auto_ptr被看成返回值返回时,将拥有权转交给调用端。指针
std::auto_ptr<ClassA> fun() { std::auto_ptr<ClassA> ptr(new ClassA); ... return ptr; } void gun() { std::auto_ptr<ClassA> ptr; for (int i=0; i<10; i++) { p = fun(); //一旦进入循环再次执行赋值动做,意味着ptr先前拥有的对象被销毁了。 ... } }
三、const std::auto_ptr<class T> ptr;ptr的拥有权不容许被转移。在这里,关键词const并不是意味着你不能更改auto_ptr所拥有的对象,而是意味着你不能更改auto_ptr的拥有权。例如:code
std::auto_ptr<int> f() { const auto_ptr<int> p(new int); auto_ptr<int> q(new int); *p = 42; //ok q = p; //error p = q; //error return p; //error }
四、并不存在针对array设计的auto_ptr。由于auto_ptr是透过delete而非delete[]来释放其所拥有的对象。
五、auto_ptr不知足STL标准容器的对其元素的要求。由于在拷贝和赋值动做以后,本来的auto_ptr和新产生的auto_ptr并不相等。本来的auto_ptr会交出拥有权,而不是拷贝给新的auto_ptr。
六、auto_ptr不是引用计数型的指针——这种指针保证,若是有一组智能型指针指向同一个对象,那么当且仅当最后一个智能型指针被注销时,该对象才会被摧毁。对象
运用实例:内存
#include <iostream> #include <memory> using namespace std; template <class T> ostream& operator<< (ostream& strm, const auto_ptr<T>& p) { if (NULL == p.get()) { strm << "NULL"; } else { strm << *p; } return strm; } int main() { auto_ptr<int> p(new int(42)); auto_ptr<int> q; cout << "after initialization:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; q = p; cout << "after assigning auto pointers:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; *q += 13; p = q; cout << "after change and reassignment:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; return 0; }
注意:output操做符的第二个参数是一个const refernce,因此并无发生拥有权的转移。
七、不能以通常指针的赋值手法来初始化一个auto_ptr:资源
std::auto_ptr<int> p(new int(42)); //OK std::auto_ptr<int> p = new int(24); //ERROR p = std::auto_ptr<int>(new int(24)); //OK p = new int(24); // ERROR
下面一个例子展现const auto_ptr的特性:
#include <iostream> #include <memory> using namespace std; template <class T> ostream& operator<< (ostream& strm, const auto_ptr<T>& p) { if (NULL == p.get()) { strm << "NULL"; } else { strm << *p; } return strm; } int main() { const auto_ptr<int> p(new int(42)); const auto_ptr<int> q(new int(0)); const auto_ptr<int> r; cout << "after initialization:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; cout << "r: " << r << endl; *q = *p; //*r = *p; //ERROR:undefine behavior *p = -77; cout << "after assigning auto pointers:" << endl; cout << "p: " << p << endl; cout << "q: " << q << endl; cout << "r: " << r << endl; //q = p; //ERROR at compile time //r = p; //ERROR at compile time return 0; }
注意下列赋值操做是错误的: *r = *p; 这个句子对于一个“未指向任何对象”的auto_ptr进行提领操做。C++标准规定,这会致使未定义行为,好比说致使程序的崩溃。