最近我从C ++ 11开始。
我研究了weak_ptr
。有两种获取原始指针的方法。
lock()
功能
shared_ptr<Foo> spFoo = wpPtr.lock();
if(spFoo) {
spFoo->DoSomething();
}
expired()
功能
if(!wpPtr.expired())
{
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
哪种方式更好?这两种方式有什么不同?
答案 0 :(得分:11)
所以共享ptr和weak ptr是线程安全的,因为如果你有一个给定线程本地对象的实例,并且它们共享一个共同的指向对象,你可以在一个线程和另一个线程中与它们进行交互。一切正常。
为了使其正常工作,您必须正确使用它们。
wp.expired()
仅用于执行“从缓冲区中删除每个过期的弱ptr”之类的操作。它对你说的目的没用。
每个弱指针一旦过期,仍会过期。但是,在您确认参与后,一个参与的弱指针可能会过期而过期。
if(!wpPtr.expired()) {
// <<--- here
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
在<<--- here
我们知道 nothing 关于多线程环境中wpPtr
的状态。它可能已过期或未过期。另一方面:
if(wpPtr.expired()) {
// <<--- there
}
在<<--- there
我们做知道弱指针已过期。
与文件io和其他类型的“事务”操作一样,检查是否可以执行某些操作的唯一方法是尝试执行此操作。在确定您应该能够执行此操作之间,状态可能会发生变化并且操作可能会失败。
你有时可以确定你几乎肯定不能早做,这有时是有用的,但你不能确定你可以做到这一点,直到你尝试。尝试尝试可能会失败,此时您将处理错误。
if(auto spFoo = wpPtr.lock()) {
spFoo->DoSomething();
}
这是与弱指针交互的“正确”方式。测试弱指针的有效性并在同一操作中获取共享指针。
在spFoo
标题之外创建if()
是可以接受的,我更喜欢这种技术,因为spFoo
的范围仅限于它有效的区域。
另一种首选技术是提前退出,您已将代码编写为SFINAE友好:
auto spFoo = wpPtr.lock();
if(!spFoo) return error("wp empty");
spFoo->DoSomething();
使代码流的“预期”执行在一条扁平线上,没有缩进或条件或跳转。
答案 1 :(得分:5)
第二个变体有两个问题:
wpPtr.expired()
if (spFoo)
spFoo
醇>
第一个变体是事务性的,是最终需要使用弱指针引用的对象时使用的变体。
答案 2 :(得分:2)
选项1 。
如果您使用选项2,则在致电wpPtr.lock()
和致电weak_ptr
之间,spFoo->DoSomething()
可能已过期且行shared_ptr
将尝试取消引用空{{1} }}
答案 3 :(得分:1)
以下是weak_ptr
的相关操作。您应该使用选项1 ,因为方法2不是线程安全的。
如果
w.use_count()
与shared_ptr
共享所有权的w
个数w.expired()
为零,则
true
会返回w.use_count()
,否则会返回false
w.lock()
如果expired
为true
,则返回空shared_ptr
;否则将shared_ptr
返回到w
指向的对象。
(2)非线程安全
// let p be the last shared_ptr pointing at the same object as wpPtr
if (!wpPtr.expired())
{
// we enter the if-statement because wpPtr.use_count() is 1
// p goes out of scope on its thread, the object gets deleted
shared_ptr<Foo> spFoo = wpPtr.lock(); // null shared_ptr
spFoo->DoSomething(); // ERROR! deferencing null pointer
}
(1)线程安全
// let p be the last shared_ptr pointing at the same object as wpPtr
shared_ptr<Foo> spFoo = wpPtr.lock();
// now, wpPtr.use_count() is 2, because spFoo and p are both pointing at the object
// p goes out of scope on its thread, but spFoo is still pointing at the object
if(spFoo) {
spFoo->DoSomething(); // OK! safe to dereference
}
答案 4 :(得分:0)
std::weak::lock
有效返回
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
使用expired来检查底层对象是否有效并锁定以将对象提升为std::shared_ptr