智能指针auto,unique&shared

智能指针

当我们使用指针在堆上分配空间时,大部分人的做法都是指针完成任务的时候使用delete操作符进行释放。但是总有意外产生。

void remodel(std::string str)
{
	std::string * ps = new std::string(str);
	...
	if(weird_thing())
	{
	throw exception();
	}
	str = *ps;
	delete ps;
	return ;
}

当上述代码出现异常时,delete将不被执行,因此也会导致内存泄漏。
智能指针是很解决这个问题的一种有效手段。

智能指针在到期时可以自动释放堆区上的内存,但是值得注意的是智能指针不能用于非堆内存。

#include<iostream>
#include<memory>
#include<string>
using namespace std;

class Report 
{
private:
	string str;

public:
	Report(const string s) : str(s) 
	{
		cout << "Object create!" << endl;
	}
	~Report() 
	{
		cout << "Object destory!" << endl;
	}

	void comment() const
	{
		cout<< str <<endl;
	}
};

int main() 
{
	//虽然都在堆区开辟了空间,但是都调用了析构函数
	{
		auto_ptr<Report> ps(new Report("using auto_ptr"));
		ps->comment();
	}

	{
		shared_ptr<Report> ps(new Report("using auto_ptr"));
		ps->comment();
	}
	
	{
		unique_ptr<Report> ps(new Report("using auto_ptr"));
		ps->comment();
	}
	//值得说明的一点是,智能指针不能应用于非堆内存
	system("pause");
	return 0;
}

在这里插入图片描述
三种智能指针都在到期的时候调用了析构函数,释放了堆区的内存

注意事项:
如果有两个以上的智能指针指向同一块内存,那么这两个指针到期的时候这一块内存会被释放两次,这是不能够接受的。要避免这种问题,可以使用如下的解决方法:
1.定义赋值运算符,避免浅拷贝。
2.建立所有权概念,对于特定的对象只有一个智能指针可以拥有它。
3.创建智能更高的指针,跟踪饮用特定对象的智能指针数。这成为称为引用计数。这是shared_ptr采用的策略。

shared_ptr和auto_ptr

事实上,再这样使用auto_ptr指针时,程序也会发生崩溃

#include<iostream>
#include<memory>
#include<string>
using namespace std;

int main() 
{
	auto_ptr<string> film[5] =
	{
		auto_ptr<string> (new string("aaaaa")),
		auto_ptr<string>(new string("bbbbb")),
		auto_ptr<string>(new string("ccccc")),
		auto_ptr<string>(new string("ddddd")),
		auto_ptr<string>(new string("fffff"))
	};
	auto_ptr<string> pwin;
	pwin = film[2];
	for(int i = 0; i < 5; ++i) cout << *film[i] << endl;
	cout << *pwin << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
上述这段代码,通过赋值操作,film[2]所指向的内存区域被转交给pwin,这导致film[2]对象不在引用该字符串。这是因为auto_ptr采用的是所有权模型,在同一时刻,只能允许一个对象只能有一个智能指针可以指向。

解决上述代码只需要将其中的auto_ptr换成shared_ptr即可。这是因为在shared_ptr内部采用的是引用计数,使得多个shared_ptr指针可以指向同一个对象

unique_ptr和auto_ptr

假设有如下的语句

auto_ptr<string> a(new string("aaa"));
auto_ptr<string> b;
b = a;

对于auto_ptr来说,在赋值之后,a会指向一块无效内存,编译器却不自知!

如果使用unique_ptr

unique_ptr<string> a(new string("aaa"));
unique_ptr<string> b;
b = a;

编译器第三条语句就会报错,避免了a指向无效数据的问题。因此,unique_ptr比auto_ptr更加安全。在编译起就能发现的错误,比运行时在产生的错误好太多了。

但是并不是所有情况下,上述赋值都会出错,尤其在使用unique_ptr的时候,考虑如下代码:

unique_ptr<string> demo(char * s)
{
	unique_ptr temp (new string(s));
	return temp;
}
...
{
...
unique_ptr<string> a ;
a = demo("test");
...
}

上个时候,demo返回了一个临时变量unique_ptr,在a接管了地址之后,temp马上被销毁。在这种情况下,编译器允许这种赋值!
也就是说,如果赋值的对象时unique_ptr类型的临时右值,那么这种操作会被编译器允许,实际上在运行时也不会产生错误。

如果想执行赋值操作,可以使用std::move()函数
另外,unique_ptr还能和new[]一起使用,这是auto_ptr和shared_ptr都做不到的事情。

std::unique_ptr<double[]> pds(new double(5));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值