你可能经常性的干如下的事情。
void remodel(std::string & str)
{
std::string *ps = new std::string(str);
str = ps;
return;
}
其实你也不愿意会发生上述事情,一般来说,程序员写的是接口,外部调用该函数的时候,久而久之会发现内存水涨船高,归根结底就是内存泄露导致的。
虽然你可以每次很注意要delete,但是保不齐你不需要立即释放,或者也会遗漏忘记,甚至你不知道什么时候释放。然道没有一种方法能帮你跳出这种“处境”吗?
本文所有说得就是运用c++标准库提供的智能指针。简单来说,
智能指针(智能指针模板类)是行为类似于指针的类对象。用于帮助管理动态内存分配的智能指针模板。
虽然有析构函数的存在,也只能解决类对象的释放。始终不能解决指针的释放。
C++98提供了auto_ptr(C++11已将其摒弃),C++11提供了另外两种解决方案,unique_ptr, shared_ptr。
使用方法如下:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class Report
{
private:
string str;
public:
Report(const string s) :str(s) { cout << "Object Created!" << endl; }
~Report() { cout << "Object Deleted" << endl; }
void comment() const { cout << str << endl; }
};
void main()
{
{
auto_ptr<Report> ps(new Report("using auto_ptr"));
ps->comment();
}
{
shared_ptr<Report> ps(new Report("using shared_ptr"));
ps->comment();
}
{
unique_ptr<Report> ps(new Report("using unique_ptr"));
ps->comment();
}
system("pause");
return;
}
所有智能指针都有explicit构造函数,只能显示调用。
shared_ptr<double> pd;
double *p_reg = new double;
pd = p_reg; //不允许
pd = shared_ptr<double>(new double); //允许
shared_ptr<double> pshared = p_reg; // 不允许
shared_ptr<double> pshared(p_reg); //允许
一、为什么C++11要摒弃auto_ptr:
void main()
{
/*auto_ptr<string> ps(new string("hello"));
auto_ptr<string> vocation;
ps = vocation;*/
auto_ptr<string> film[5] =
{
auto_ptr<string>(new string("1")),
auto_ptr<string>(new string("2")),
auto_ptr<string>(new string("3")),
auto_ptr<string>(new string("4")),
auto_ptr<string>(new string("5"))
};
auto_ptr<string> pwin;
pwin = film[2];
for (int i = 0; i < 5; i++)
cout << *film[i] << endl;
system("pause");
return;
}
程序奔溃原因在于,程序将所有权从film[2]转让给pwin,导致film[2]不再引用该字符串,当打印film[2]指向的字符串时,发现这是一个空指针。
解决方法:把auto_ptr改成shared_ptr,
shared_ptr的原理是采用引用计数,当pwin和film[2]指向同一个对象时,引用计数从1增加到2,在程序末尾,后声明的pwin先调用其析构函数,该析构函数将引用计数-1,变成了1,然后shared_ptr数组成员释放,将引用计数从1变成0,释放以前分配的空间。
二、为何unique_ptr优于auto_ptr
如果出现下列语句
unique_ptr<string> ps3(new string("auto"));
unique_ptr<string> ps4;
ps3 = ps4; #编译器认为该句非法
unique_ptr可防止p3和p4的析构函数释放同一个对象。
但是如果像下列语句
unique_ptr<string> demo(const char * s)
{
unique_ptr<string> temp(new string(s));
return temp;
}
void main()
{
unique_ptr<string> ps;
ps = demo("Uniquely special");
}
demo函数返回一个临时的unique_ptr,ps接管了temp的所有权(其实调用了unique_ptr的拷贝构造),因为demo生成的是右值
出了这语句temp就被销毁。
总之,编译器支持这种语法,如果源unique_ptr将存在一段时间,则编译器禁止这样做。
unique_ptr相比于auto_ptr还有另外一个优点,它有一个可用于数组的变体。
模板auto_ptr支持new和delete但是不支持new[]和delete[],unique_ptr却可以。
unique_ptr<double[]> pda(new double(5));
三、如何选择智能指针
如果程序要使用多个指向同一个对象的指针,应选择shared_ptr,如果你的编译器没有提供,可以选择boost库中的shared_ptr
相反,可以是用unique_ptr,如果编译器没有提供,可以考虑使用boost库中的scoped_ptr,它与unique_ptr类似。
最好不要用auto_ptr。