C++学习之auto_ptr智能指针
来源:互联网 发布:mac 怎么设置无线鼠标 编辑:程序博客网 时间:2024/05/01 00:28
auto_ptr的设计动机
函数的操作经常是依以下模式进行:
1.获取一些资源。
2.执行一些操作。
3.释放所获取的资源。
如果一开始获取的资源被绑定在局部对象上,当函数退出时,它们的析构函数被调用,从而自动释放这些资源。然而事情并不总是如此顺利,如果资源是以显示(explicitly)获得,而且没有被绑定在任何对象上,那就需要以显示手法释放。这种情形常常发生在指针上。
如下一个运用new和delete来产生和销毁对象的典型例子:
void f() { ClassA* ptr = new ClassA; //create an object explicitly... //perform some operationsdelete ptr; //clean up (destroy the object explicitly)}如果在delete对象之前,函数就返回了或出现异常而退出,那么函数就根本不会调用delete语句。这很可能造成资源泄露,而防止这种资源泄露的常见办法就是捕获所有异常,但这会使程序代码变得非常复杂和累赘。
如果使用智能指针,情形就会大不一样。这个智能指针应该保证,无论在何种情形下,只要自己被摧毁,就一定连带释放其所指资源。而由于智能指针本身就是区域变量,所以无论是正常退出,还是异常退出,它一定会被销毁。auto_ptr正是这种指针。
auto_ptr是这样一种指针:它是“它所指对象”的拥有者。所以,当身为对象拥有者的auto_ptr被摧毁时,该对象也将遭到摧毁。auto_ptr要求一个对象只能有一个拥有者,严禁一物二主。
#include <memory> void f() { //create and initialize anauto_ptr std::auto_ptr<ClassA> ptr(new ClassA); ... //perform some operations}通过使用智能指针,不再需要delete,也不需要捕获异常。不过注意:auto_ptr<>不允许使用一般指针惯用的赋值初始化方式。你必须直接使用数值来完成初始化:
std::auto_ptr<ClassA> ptr1(new ClassA); //OKstd::auto_ptr<ClassA> ptr2 = new ClassA; //ERRORauto_ptr拥有权的转移
auto_ptr所界定的是一种严格的拥有权观念。也就是说,由于一个auto_ptr会删除其所指对象,所以这个对象绝对不能同时被其他对象“拥有”。绝对不应该出现多个auto_ptr同时拥有一个对象的情况。
这个条件会使auto_ptr的copy构造函数和assignment操作符的实现有所不同:copy构造函数和assignment操作符会将对象拥有权交出去。
//initialize anauto_ptr with a new objectstd::auto_ptr<ClassA> ptr1(new ClassA); //copy theauto_ptr //- transfers ownership fromptr1 toptr2 std::auto_ptr<ClassA> ptr2(ptr1);此时ptr2指向原ptr1所指对象,而ptr1现在指向NULL。而且要注意:只有auto_ptr可以拿来当做另一个auto_ptr的初值,普通指针是不行的:
std::auto_ptr<ClassA> ptr; //create anauto_ptr ptr = new ClassA; //ERRORptr = std::auto_ptr<ClassA>(new ClassA); //OK, delete old object // and own new拥有权的转移,使得auto_ptr产生一种特殊用法:某个函数可以利用auto_ptr将拥有权转交给另一个函数。这种事情可能发生在两种情形下:
- 某函数是数据的终点。如果auto_ptr以传值方式被当做一个参数传递给某函数,就有这种情况。此时被调用端的参数获得这个auto_ptr的拥有权,如果函数不再将它传递出去,它所指的对象就会在函数退出时被删除。
- 某函数是数据的起点。当一个auto_ptr被返回,其拥有权便被转交给调用者了。
auto_ptr作为成员之一
如果你以auto_ptr而非一般指针作为成员,当对象被删除时,auto_ptr会自动删除其所指的成员对象,于是你也就不再需要析构函数了。此外,即使在初始化期间抛出异常,auto_ptr也可以帮助避免资源泄漏。注意,只有当对象被完全构造成功,才有可能于将来调用其析构函数。这就造成了资源泄漏的隐患:如果第一个new成功了,第二个new却失败了,就会造成资源泄漏。例如:
class ClassB { private: ClassA* ptr1; //pointer membersClassA* ptr2; public: //constructor that initializes the pointers//- will cause resource leak if secondnew throwsClassB (ClassA val1, ClassA val2) : ptr1(new ClassA(val1)), ptr2(new ClassA(val2)) { } //copy constructor//- might cause resource leak if second new throwsClassB (const ClassB& x) : ptr1(new ClassA(*x.ptr1)), ptr2(new ClassA(*x.ptr2)) { } //assignment operatorconst ClassB& operator= (const ClassB& x) { *ptr1 = *x.ptr1; *ptr2 = *x.ptr2; return *this; } ~ClassB () { delete ptr1; delete ptr2; } ... };使用auto_ptr,你可以轻松避免这场悲剧:
class ClassB { private: const std::auto_ptr<ClassA> ptr1; //auto_ptr membersconst std::auto_ptr<ClassA> ptr2; public: //constructor that initializes theauto_ptrs//- no resource leak possibleClassB (ClassA val1, ClassA val2) : ptr1 (new ClassA(val1)), ptr2(new ClassA(val2)) { } //copy constructor//- no resource leak possibleClassB (const ClassB& x) : ptr1(new ClassA(*x.ptr1), ptr2(new ClassA(*x.ptr2)) { } //assignment operatorconst ClassB& operator= (const ClassB& x) { *ptr1 = *x.ptr1; *ptr2 = *x.ptr2; return *this; } //no destructor necessary//(default destructor letsptr1 andptr2 delete their objects)... };auto_ptr的错误运用
(1)auto_ptr之间不能共享使用权
一个auto_ptr千万不能指向另一个auto_ptr(或其他对象)所拥有的对象。否则,当第一个指针删除该对象后,另一个指针突然间指向了一个已被销毁的对象,那么,如果再使用那个指针进行读写操作,就会引发一场灾难。
(2)并不存在针对array而设计的auto_ptr
auto_ptr不可以指向array,因为auto_ptr是透过delete而非delete[]来释放其所拥有的对象。
(3)auto_ptr绝非一个“四海通用”的智能指针
并非任何使用智能指针的地方,都适用auto_ptr。特别注意,它不是引用计数型指针——这种指针保证,如果有一组智能型指针指向一个对象,那么当且仅当最后一个智能指针被销毁时,该对象才会被销毁。
(4)auto_ptr不满足STL容器对其元素的要求
auto_ptr并不满足STL容器对于元素的最基本要求,因为在拷贝和赋值动作之后,原本的auto_ptr和新产生的auto_ptr并不相等。
auto_ptr类别的实作示范
// util/autoptr.hpp/* classauto_ptr *- improved standard conforming implementation */namespace std { //auxiliary type to enable copies and assignments (now global)template<class Y> struct auto_ptr_ref { Y* yp; auto_ptr_ref (Y* rhs) : yp(rhs) { } }; template<class T> class auto_ptr { private: T* ap; //refers to the actual owned object (if any)public: typedef T element_type; //constructorexplicit auto_ptr (T* ptr = 0) throw() : ap(ptr) { } //copy constructors (with implicit conversion)//- note: nonconstant parameterauto_ptr (auto_ptr& rhs) throw() : ap (rhs. release()) { } template<class Y> auto_ptr (auto_ptr<Y>& rhs) throw() : ap(rhs.release()) { } //assignments (with implicit conversion)//- note: nonconstant parameterauto_ptr& operator= (auto_ptr& rhs) throw() { reset(rhs.release()); return *this; } template<class Y> auto_ptr& operator= (auto_ptr<Y>& rhs) throw() { reset(rhs.release()); return *this; } //destructor~auto_ptr() throw() { delete ap; } //value accessT* get() const throw() { return ap; } T& operator*() const throw() { return *ap; } T* operator->() const throw() { return ap; } //release ownershipT* release() throw() { T* tmp(ap); ap = 0; return tmp; } //reset value void reset (T* ptr=0) throw(){ if (ap != ptr) { delete ap; ap = ptr; } } /* special conversions with auxiliary type to enable copies and assignments*/auto_ptr(auto_ptr_ref<T> rhs) throw() : ap(rhs.yp) { } auto_ptr& operator= (auto_ptr_ref<T> rhs) throw() { //newreset(r.yp); return *this; } template<class Y> operator auto_ptr_ref<Y>() throw() { return auto_ptr_ref<Y>(release()); } template<class Y> operator auto_ptr<Y>() throw() { return auto_ptr<Y>(release()); } }; }
- 【C++】智能指针auto_ptr
- C++学习之auto_ptr智能指针
- 智能指针之auto_ptr
- 智能指针之 auto_ptr
- 智能指针之auto_ptr
- 智能指针之auto_ptr
- 智能指针之 Auto_Ptr
- 智能指针之auto_ptr
- c++ auto_ptr智能指针详解
- STL之auto_ptr智能指针
- C++智能指针之auto_ptr
- C++智能指针之auto_ptr
- C++智能指针之auto_ptr
- C++细节学习之智能指针auto_ptr和tr1::shared_ptr
- 【C/C++和指针】auto_ptr智能指针
- 【C/C++】智能指针auto_ptr,share_ptr,unique_ptr
- 【C++】智能指针auto_ptr的简单实现
- C++——模版:智能指针auto_ptr
- Pocketsphinx语音识别-----语言模型训练和声学模型的适应过程
- ShadowGun Shaders
- request.getParameter() 、 request.getInputStream()和request.getReader() 使用体会
- MOCK技术,核心代码!
- Android程序对不同手机屏幕分辨率自适应的总结
- C++学习之auto_ptr智能指针
- 物联网时代,智能家居到底离我们有多远
- 手机九宫格加密种数
- 网络通讯框架-Volley源码分析(2)
- 浅谈Lean UX:我们到底该怎么设计?
- 如何美化你的.net 应用程序 (皮肤使用)
- asp.net中把日期(2014/03/25)和时间(14:00)拼接成完整的时间类型
- linux spi驱动
- 一个简单的demo学习Android远程Service(AIDL的使用