所谓资源就是,一旦使用了它,未来必须还给系统。C++最常使用的资源就是动态分配内存(若是分配了内存却不释放,会致使内存泄露),但内存只是必需要管理的众多资源之一。其余常见的资源还包括文件描述器(file descriptors)、互斥锁(mutex locks)、图形界面中的字型和笔刷、数据库链接、以及网络sockets。不论哪种资源,重要的是,当再也不使用它时,必须将它还给系统。html
假设咱们使用一个用来模拟投资行为(例如股票、债券等)的程序库,其中各式各样的投资类型继承自一个root class Investment:数据库
class Investment { ... //"投资类型" 继承体系中的root class };
进一步假设,这个程序库系经过一个工厂函数供应咱们某特定的Investment对象:数组
Investment* createInvestment(); //返回指针,指向Investment继承体系内的动态分配对象。调用者有责任删除它。
//这里为了简化,不写参数
为确保createInvestment返回的资源老是被释放,把资源放进对象内,咱们即可依赖C++的“析构函数自动调用机制”确保资源被释放。安全
许多资源被动态分配在heap堆内然后被用于单一区块或函数内。它们应该在控制流离开那个区块或函数时被释放。标准程序库提供的auto_ptr正是针对这种形式而设计的特制产品。auto_ptr是个“类指针(pointer-like)对象”,也就是所谓的“智能指针”,其析构函数自动对其所指对象调用delete。下面示范如何使用auto_ptr以免f函数潜在的资源泄露可能性:网络
void f() { std::auto_ptr<investment> pInv(createInvestment()); //调用工厂函
... //一如既往地使用pInv
//经由auto_ptr的析构函数自动删除pInv }
这个简单的例子示范了“以对象管理资源”的两个关键想法:socket
一、得到资源或马上放进管理对象(managing object)内。以上代码中的createInvestment返回的资源被当作其管理者auto_ptr的初值。实际上“以对象管理资源”的观念常被成为“资源取得时机即是初始化时机”(Resource Acquisition Is Initialization;RAII),由于咱们几乎老是在得到一笔资源后于同一语句内以它初始化某个管理对象。函数
二、管理对象(managing object)运用析构函数确保资源被释放。不论控制流如何离开区块,一旦对象被销毁(例如当对象离开做用域)其析构函数天然会被自动调用因而资源被释放。测试
注意:因为auto_ptr被销毁时会自动删除它所指之物,因此必定要注意别让多个auto_ptr同时指向同一个对象。不然若对象被删除一次以上,会出现“未定义行为”的错误,为了预防这个问题,auto_ptr有个一特殊性质:若经过copy构造函数或copy assignment操做符复制它们,它们会变成null,而复制所得的指针将取得资源的惟一拥有权!ui
std::auto_ptr<Investment> pInv1(CreateInvestment()); //pInv1指向CreateInvestment返回物
std::auto_ptr<investment> pInv2(pInv1); //如今pInv2指向对象,pInv1被设为null
pInv1 = pInv2; //如今pInv1指向对象,pInv2被设为null
auto_ptr的替代方案是“引用计数型智慧指针”(reference-counting smart pointer; RCSP)。所谓RCSP也是个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。RCSP提供的行为类型垃圾回收,不一样的是RCSP没法打破环状引用(cycles of reference,例如两个其实已经没有被使用的对象彼此互指,于是好像还处在“被使用”状态)。spa
TR1的tr1::shared_ptr(见条款54)就是个RCSP,因此能够这样写f:
void Func() { ... std::tr1::shared_ptr<Investment> pInv1(createInvestment()); //pInv1指向crateInvestment返回物 std::tr1::shared_ptr<Investment> pInv2(pInv1); //pInv1和pInv2指向同一个对象 pInv1 = pInv2; //同上,无任何改变 ... } //函数结束后,pInv1和pInv2被销毁,它们所指的对象也被自动销毁
由于auto_ptr并非天衣无缝的,它的确很方便,但也有缺陷,在使用时要注意避免。首先,不要将auto_ptr对象做为STL容器的元素。C++标准明确禁止这样作,不然可能会碰到不可预见的结果。
auto_ptr和tr1::shared_ptr二者都在其析构函数内作delete而不是delete[]动做。故不能讲动态分配的数组上使用auto_ptr或tr1::shared_ptr。例如:
std::auto_ptr<std::string> aps(new std::string[10]); //错误!会用上错误的delete形式
std::tr1::shared_ptr<int> spi(new int[1024]); //错误!会用上错误的delete形式
请牢记:
一、为防止内存泄露,请使用RAII对象,它们在构造函数中得到资源并在析构函数中释放资源。
二、两个常被使用RAII class分别是trl1::shared_ptr和auto_ptr。trl1::shared_ptr一般是较佳选择,由于其copy行为比较直观。若选择auto_ptr,复制动做会使被复制物指向null。trl1::shared_ptr在头文件<memory>中
而后收集了关于auto_ptr的几种注意事项:
一、auto_ptr不能共享全部权。
二、auto_ptr不能指向数组
三、auto_ptr不能做为容器的成员。
四、不能经过赋值操做来初始化auto_ptr
std::auto_ptr<int> p(new int(42)); //OK
std::auto_ptr<int> p = new int(42); //ERROR
这是由于auto_ptr 的构造函数被定义为了explicit
五、不要把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)。