C++——智能指针

你可能经常性的干如下的事情。

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。

猜你喜欢

转载自blog.csdn.net/u012198575/article/details/83415879