lock()和expired()之间的差异是什么? weak_ptr C ++

时间:2016-06-07 12:39:09

标签: c++ c++11 shared-ptr smart-pointers weak-ptr

最近我从C ++ 11开始。 我研究了weak_ptr。有两种获取原始指针的方法。

  1. lock()功能

    shared_ptr<Foo> spFoo = wpPtr.lock();
    
    if(spFoo) {
        spFoo->DoSomething();
    }
    
  2. expired()功能

    if(!wpPtr.expired())
    {
        shared_ptr<Foo> spFoo = wpPtr.lock();
        spFoo->DoSomething();
    }
    
  3. 哪种方式更好?这两种方式有什么不同?

5 个答案:

答案 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)

第二个变体有两个问题:

  1. 执行不必要的检查wpPtr.expired()
  2. 在解除引用if (spFoo)
  3. 之前,它缺少必要的支票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()如果expiredtrue,则返回空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)

引用cppreference.com

std::weak::lock有效返回

expired() ? shared_ptr<T>() : shared_ptr<T>(*this)

使用expired来检查底层对象是否有效并锁定以将对象提升为std::shared_ptr