指针的缺陷
using std::string;
void remodel(string &str) {
string *ps = new string (str);
str = *ps;
return ;
}
你可能已经发现了其中的缺陷。remodel函数每次被调用时都会申请一段内存,但是从不收回。这样会导致内存泄漏。解决方法是在return语句前添加释放内存的语句。
delete ps;
但是当遇到下面这种情况时,你可能会忘了释放内存。
using std::string;
void remodel(string &str) {
string *ps = new string (str);
if(wrong()) {//we get something wrong
throw exception();
}
str = *ps;
delete ps;
return;
}
如果程序出现异常,throw将直接实现跳转,delete语句不会被执行,内存无法释放。
常用的智能指针类
=============
为了解决这个问题,STL设计了三种智能指针模版:auto_ptr、unique_ptr和shared_ptr。可以将new获得的地址赋给这种对象。
要使用智能指针模版,首先需要包含头文件memory。
#include <memory>
以下是修改过的remodel函数
using std::string;
using std::auto_ptr;
void remodel(string &str) {
auto_ptr <string> ps (new string (str));
if(wrong())
throw exception();
str = *ps;
return;
}
每个智能指针都将存放在一个代码块里,这样离开代码块时,指针将过期。
智能指针模版类的定义方式决定了智能指针对象很多方面都类似常规指针比如可以访问结构成员、赋值给指向相同类型的常用指针。
三种智能指针的应用范围
==================
首先我们来看一段代码
auto_ptr<string> p1(new string("auto"));
auto_ptr<string> p2;
p2 = p1;
在赋值语句中,p2接管了string对象的所有权后,p1的所有权将被剥夺。这是智能指针的一个特性,以防止p1和p2的析构函数销毁相同的对象。但是如果程序随后想要用到p1对象,则会发生错误。
unique_ptr和shared_ptr分别以两种不同的方式解决了这个问题。在unique_ptr中,赋值语句将会出现报错信息。当程序试图将一个unique_ptr赋给另外一个的时候,如果源unique_ptr是一个临时右值,很快会被销毁,没有机会使用它访问无效的数据,编译器便不会报错。当如果你要执意执行赋值时,而编译器又会出现报错时,请使用move函数,但是需要处理好对象间的关系。
unique_ptr <int> p1(new string("unique"));
unique_ptr <int> p2;
p2 = move(p1);
而shared_ptr则以一种更智能的方式来解决这类问题。shared_ptr会跟踪引用特定对象的智能指针数。这成为引用计数。如赋值时,指针计数+1,指针过期时,计数-1。仅当最后一个指针过期时,才调用delete。
如果程序要使用指向同一个对象的多个指针,应选择shared_ptr。如用一个指针数组指示数据并辅助用一些指针来标示特定元素(最大最小值)。
这种情况就需要shared_ptr。而在其他情况下,不需要多个指向同一个对象的指针,则建议使用unique_ptr。实际上在C++11中,auto_ptr已经被摒弃。