lock() 和 expired() 有什么区别? weak_ptr C++
What is diffrence between lock() and expired()? weak_ptr C++
最近我开始学习 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();
}
哪种方法更好?这两种方式有什么不同?
引用自cppreference.com:
std::weak::lock
有效 returns
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
使用 expired 检查底层对象是否有效并锁定以潜在地将对象提升为 std::shared_ptr
选项 1.
如果您选择选项 2,那么在调用 wpPtr.expired()
和调用 wpPtr.lock()
之间 weak_ptr
可能已经过期并且行 spFoo->DoSomething()
将尝试取消引用空 shared_ptr
.
第二个变体有两个问题:
- 它进行了不必要的检查
wpPtr.expired()
- 取消引用前缺少必要的检查
if (spFoo)
spFoo
第一个变体是事务性的,当您最终需要使用弱指针引用的对象时使用该变体。
所以 shared ptr 和 weak ptr 是线程安全的,因为如果你有一个给定线程本地的 object 实例,并且它们共享一个公共的 pointed-to object ,您可以在一个线程和另一个线程中与他们交互,一切正常。
要使其正常工作,您必须正确使用它们。
wp.expired()
仅对执行诸如“从缓冲区中删除每个过期的弱指针”之类的事情有用。它对您提出的目的没有用。
每个弱指针一旦过期,就会保持过期状态。但是,一个已启用的弱指针在您确认它已启用后可能会立即过期。
if(!wpPtr.expired()) {
// <<--- here
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
在 <<--- here
,我们对 multi-threaded 环境中 wpPtr
的状态一无所知。它可能已过期或未过期。另一方面:
if(wpPtr.expired()) {
// <<--- there
}
在 <<--- there
我们 做 知道弱指针已过期。
与文件 io 和其他类型的“事务性”操作一样,检查您是否可以做某事的唯一方法是尝试去做。在确定你应该能够做到这一点和做到这一点之间,状态可能会改变并且操作可能会失败。
您有时会发现您几乎肯定无法尽早做到,这有时很有用,但您不能确定自己是否可以做到,除非您尝试过。尝试尝试可能会失败,此时您处理错误。
if(auto spFoo = wpPtr.lock()) {
spFoo->DoSomething();
}
这是与弱指针交互的“正确”方式。测试弱指针的有效性,并在同一操作中获取共享指针。
在 if()
header 之外创建一个 spFoo
是可以接受的,我更喜欢这种技术,因为 spFoo
的范围完全限于它所在的区域有效。
另一种首选技术是提前退出:
auto spFoo = wpPtr.lock();
if(!spFoo) return error("wp empty");
spFoo->DoSomething();
这使得代码的“预期”执行在一条直线上流动,没有缩进、条件或跳转。
下面是weak_ptr
的相关操作。你应该选择 选项 1 因为方法 2 不是线程安全的。
w.use_count()
The number of shared_ptr
s that share ownership with w
w.expired()
returns true
if w.use_count()
is zero, false
otherwise
w.lock()
If expired
is true
, returns a null shared_ptr
; otherwise returns a shared_ptr
to the object to which w
points.
(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
}
最近我开始学习 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(); }
哪种方法更好?这两种方式有什么不同?
引用自cppreference.com:
std::weak::lock
有效 returns
expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
使用 expired 检查底层对象是否有效并锁定以潜在地将对象提升为 std::shared_ptr
选项 1.
如果您选择选项 2,那么在调用 wpPtr.expired()
和调用 wpPtr.lock()
之间 weak_ptr
可能已经过期并且行 spFoo->DoSomething()
将尝试取消引用空 shared_ptr
.
第二个变体有两个问题:
- 它进行了不必要的检查
wpPtr.expired()
- 取消引用前缺少必要的检查
if (spFoo)
spFoo
第一个变体是事务性的,当您最终需要使用弱指针引用的对象时使用该变体。
所以 shared ptr 和 weak ptr 是线程安全的,因为如果你有一个给定线程本地的 object 实例,并且它们共享一个公共的 pointed-to object ,您可以在一个线程和另一个线程中与他们交互,一切正常。
要使其正常工作,您必须正确使用它们。
wp.expired()
仅对执行诸如“从缓冲区中删除每个过期的弱指针”之类的事情有用。它对您提出的目的没有用。
每个弱指针一旦过期,就会保持过期状态。但是,一个已启用的弱指针在您确认它已启用后可能会立即过期。
if(!wpPtr.expired()) {
// <<--- here
shared_ptr<Foo> spFoo = wpPtr.lock();
spFoo->DoSomething();
}
在 <<--- here
,我们对 multi-threaded 环境中 wpPtr
的状态一无所知。它可能已过期或未过期。另一方面:
if(wpPtr.expired()) {
// <<--- there
}
在 <<--- there
我们 做 知道弱指针已过期。
与文件 io 和其他类型的“事务性”操作一样,检查您是否可以做某事的唯一方法是尝试去做。在确定你应该能够做到这一点和做到这一点之间,状态可能会改变并且操作可能会失败。
您有时会发现您几乎肯定无法尽早做到,这有时很有用,但您不能确定自己是否可以做到,除非您尝试过。尝试尝试可能会失败,此时您处理错误。
if(auto spFoo = wpPtr.lock()) {
spFoo->DoSomething();
}
这是与弱指针交互的“正确”方式。测试弱指针的有效性,并在同一操作中获取共享指针。
在 if()
header 之外创建一个 spFoo
是可以接受的,我更喜欢这种技术,因为 spFoo
的范围完全限于它所在的区域有效。
另一种首选技术是提前退出:
auto spFoo = wpPtr.lock();
if(!spFoo) return error("wp empty");
spFoo->DoSomething();
这使得代码的“预期”执行在一条直线上流动,没有缩进、条件或跳转。
下面是weak_ptr
的相关操作。你应该选择 选项 1 因为方法 2 不是线程安全的。
w.use_count()
The number ofshared_ptr
s that share ownership withw
w.expired()
returnstrue
ifw.use_count()
is zero,false
otherwise
w.lock()
Ifexpired
istrue
, returns a nullshared_ptr
; otherwise returns ashared_ptr
to the object to whichw
points.
(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
}