C++智能指针模板类auto_ptr,unique_ptr,shared_ptr和weak_ptr

6 篇文章 2 订阅

智能指针是行为类似指针的类对象
这三个智能指针模板(auto_ptr,unique_ptr和shared_ptr)都定义了类似指针的对象,可以将new获得(直接或间接)的地址赋给这种 对象。当智能指针过期后,其析构函数使用delete来释放内存。因此,如果将new返回的地址赋给这些对象,将无需记住稍后释放内存:在智能指针过期后,这些内存将自动被释放。
要创建智能指针对象,必须包含头文件memory,该文件模板定义。然后使用通常的模板语法来实例化所需类型的指针。例如,模板auto_ptr包含如下的构造函数:

template <class X> class auto_ptr{
public:
	explicit auto_ptr(X* p = 0) throw();
	...
}

throw()意味着构造函数不会引发异常。

auto_ptr<double> pd(new double);//创建一个指向double类型的auto_ptr智能指针pd
auto_ptr<string> pd(new string);//创建一个指向string类型的auto_ptr智能指针ps
unique_ptr<string> pdu(new string);//创建一个指向double类型的unique_ptr智能指针pdu
shared_ptr<string> pds(new string);//创建一个指向string类型的shared_ptr智能指针pss

智能指针模板位于std名称空间中,每个智能指针都放在一个代码块内,当离开代码块时,指针将过期。

#include <iostream>
#include<string>
#include<memory>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class Report
{
public:
	Report(const string s) :str(s) {
		cout << "Object created!\n" << endl;
	}
	~Report() {
		cout << "Object deleted!" << endl;
	}
	void comment() const {
		cout << str << endl;
	}

private:
	string str;
};


int main(void) {

	{
		std::auto_ptr<Report> ps(new Report("using autp_ptr"));
		ps->comment();
	}
	{
		std::shared_ptr<Report> ps(new Report("using shared_ptr"));
		ps->comment();
	}
	{
		std::unique_ptr<Report> ps(new Report("using unique_ptr"));
		ps->comment();
	}

	std::shared_ptr<double> pd;
	double *p_reg = new double;

	//pd = p_reg;//不允许,构造函数使用了explicit,关闭了隐式构造函数
	pd = std::shared_ptr<double>(p_reg);//允许,显式构造函数

	//std::shared_ptr<double> pshared = p_reg;//不允许,同上,隐式构造函数被关闭
	std::shared_ptr<double> pshared(p_reg);//允许,显式构造

	return 0;
}

智能指针对象的很多方面都类似于常规指针,例如,ps是一个智能指针对象,则可以对它执行解引用操作(*ps)、用它来访问结构成员(ps->puffIndex)、将它赋值给相同类型的常规指针。还可以将智能指针对象赋给另一个同类型的智能指针对象(有风险)。
对三种智能指针对象来说,都应避免如下情况:

string vacation("test");
shared_ptr<string> pvac(&vacation);//错误

pvac过期时,程序将把delete运算符用于非堆内存,这是错误的。

关于智能指针的注意事项

auto_ptr的缺陷:

auto_ptr<string> ps (new string("I reigned lonely as a cloud"));
auto<string> vocation;
vocation  = ps;

如果ps和vocation是常规指针,则两个指针将指向同一个string对象。这是不能接受的,因为程序试图将一个对象删除两次,一次是ps过期时,一次是vocation过期时。
解决办法:

  • 定义赋值运算符,使之执行深复制、深拷贝。这样两个指针将指向不同的对象,其中一个是另一个的副本。
  • 建立所有权(ownership)概念。对于特定的对象,只能有一个智能指针拥有它。这样只有拥有对象的智能指针的构造函数会删除对象。然后,让赋值操作转让所有权。这就是auto_ptr和unique_ptr的策略。但unique_ptr的策略更严格。
  • 创建智能更高的指针,跟踪引用特定对象的指针计数。称为引用计数。例如,赋值时计数加一,而指针过期时计数减一,仅当最后一个指针过期时,才调用delete,这就是shared_ptr的策略。

unique_ptr为何优于auto_ptr

auto_ptr<string> p1(new string("auto");//#1
auto_ptr<string> p2;                             //#2
p2=p1;                                                //#3

在语句#3中,p2接管string对象的所有权,p1的所有权被剥夺,这可以防止p1和p2的析构函数试图删除同一个对象:但是如果程序随后试图使用p1,这将产生错误,因为p1不再指向有效的数据。
unique_ptr的情况:

unique_ptr<string> p1(new string("auto");//#4
unique_ptr<string> p2;                   //#5
p2=p1;                                 //#6

编译器会认为#6语句非法,从而避免了p1不再指向有效数据的问题,因此unique_ptr比auto_ptr更安全。(编译阶段发现错误比程序运行时出错更安全
有时候如果前一个指针会很快地被销毁,这就不会留下危险,比如在函数中作为返回值:

unique_ptr<string> demo(const char *s){
	unique_ptr<string> temp(new string(s));
	return temp;
}

假设:

unique_ptr<string> ps;
ps = demo("Uniquely special");

demo返回的unique_ptr在赋值给ps后,被销毁。ps接管string对象的所有权。
总之,程序试图讲一个unique_ptr赋给另一个时,如果unique_ptr是临时右值,则允许,如果源unique_ptr将存在一段时间,则编译器不允许。

unique_ptr<string> pu1(new string("hello");//#1
unique_ptr<string> pu2;                   //#2
pu2=pu1;                                 //#3  不允许
unique_ptr<string> pu3;                   //#4
pu3 = unique_ptr<string>(new string("Hi"); //#5 允许,临时对象将会被销毁

如果非要执行#3这个语句,仅当以非智能的方式使用遗弃的智能指针(如解引用时),这种赋值才会不安全。要安全地重用这种指针。可以给它赋新值。C++有一个标准库函数std::move(),可以实现将一个unique_ptr赋值给另一个

unique_ptr<string>ps1,ps2;//#1
ps1=demo("Uniquely special");   
ps2 = std::move(ps1);
ps1=demo("TEST");   
cout<<*ps2<<*ps1<<endl;

相对于auto_ptr,unique_ptr还有另外一个优点。模板auto_ptr只能使用new和delete,而unique_ptr可以使用new和new[].

使用new分配内存时,才能使用auto_ptr和shared_ptr,使用new[]时,不能
unique_ptr则可以使用new和new [ ].
在这里插入图片描述

选择智能指针

  • 如果程序要使用多个指向同一个对象的指针,应选择shared_ptr。因为它有引用计数。
  • 如果不需要,就使用unique_ptr。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SOC罗三炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值