条款20:对于类似std::shared_ptr但有可能空悬的指针使用std::weak+ptr

std::weak_ptr并不是一种独立的智能指针,而是std::shared_ptr的一种扩充

std::weak_ptr一般是通过std::shared_ptr来创建的。当使用std::shared_ptr完成初始化std::weak_ptr的时刻,两者就治涉到了相同的位置,但是std::weak_ptr并不影响所指涉到的对象的引用计数:

auto spw = std::make_shared<Widget>();		// spw构造完成后,指涉到Widget的引用计数置为1
std::weak_ptr<Widget> wpw(spw);				// wpw和spw指涉到同一个Widget.引用计数保持为1
// ...
spw = nullptr;								// 引用计数变为0,Widget对象被析狗。wpw空悬

std::weak_ptr的空悬,也被称作失效,可以直接测试:

if(wpw.expired())							// 若wpw不再指涉到任何对象

一种形式是std::weak_ptr::lock,它返回一个std::shared_ptr.如果sd::weak_ptr已经失效,则std::shared_ptr为空。

考虑一个工厂函数,该函数基于唯一的ID来创建一些指涉到只读对象的智能指针。根据条款18,它返回一个std::shared_ptr:

std::unique_ptr<const Widget> loadWidget(WidgetID id);

如果loadWidget执行了文件或者数据库的I/O操作,并且ID会被频繁重复使用,一个合理优化是撰写一个能够完成loadWidget的工作,但又能缓存结果的函数。然而用缓存所用过的Widget造成缓存拥塞,可能本身就会引起性能问题,因此一个合理的优化就是缓存的Widget不再有用时將其删除。

对于这个带缓存的工厂函数而言,返回std::unique_ptr并不十分合适。缓存管理器的指针需要能够校验它们合适会空悬,因为工厂函数的用户用完由该工厂函数返回的对象后,该对象就將被析狗,此时相应的缓存条目將会空悬。因此应该缓存std::weak_ptr,一种可以检测空悬的指针。这也意味着,该工厂函数的返回值应该为std::shared_ptr,因为只有当对象的生存期托管给std::shared_ptr时,std::weak_ptr才能检测空悬。如下是带缓存的loadWidget的一个快速而粗糙的实现版本

std::shared_ptr<const Widget> fastLoadWidget(WidgetID id)
{
	static::std::unordered_map<WidgetID, std::weak_ptr<const Widget>> cache;
	auto objPtr = cache[id].lock();  //obj的类型是std::shared_ptr,指向缓存的对象
	if (!objPtr) {
		objPtr = loadWidget(id);	 //如果对象不在缓存中,则加载,并缓存
		cache[id] = objPtr;
	}
	return objPtr;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值