为什么我们需要C ++ 11中的weak_ptr?

时间:2016-04-25 23:35:08

标签: c++ c++11

我正在阅读" C ++标准库" Nicolai M. Josuttis的书,用于理解弱点。作者提到了需要有一个weak_ptr的两个原因而我没有得到第二个原因。任何人都可以提供一个简单的解释以及以下原因的例子(引自书中):

  

当您明确想要共享但不拥有对象时,会出现另一个示例。因此,您具有以下语义:对对象的引用的生命周期超过它引用的对象。在这里,shared_ptrs永远不会释放对象,普通指针可能不会注意到它们引用的对象不再有效,这会带来访问已发布数据的风险。

3 个答案:

答案 0 :(得分:8)

该语句的后半部分应该是明确的:如果指针不是拥有指针,那么它指向的对象可能会被 的任何软件删除。所有者 - 然后你就会有标准的悬空参考。

所以这个问题是:你有一些软件拥有的对象让其他软件可以访问它 - 但是其他软件不会共享所有权。所以所有者可以随时删除它,而其他软件需要知道它的指针不再有效。

也许一个例子会有所帮助:

你有一些软件正在观看一个摄像头,指出你的窗户指向一个喂鸟器,它正在识别喂食器上的鸟类,它来来去去。进给器中的每只鸟在到达进纸器时都有一个由该软件创建的对象,当该鸟飞走时该对象被删除。

与此同时,其他一些软件正在进行人口普查。它每隔10秒就从喂食器观察软件中抓取一个喂食器上的鸟类。每隔100秒就会发出一个报告,说明哪些鸟在整个100秒内都在进料器上。

因为鸟类的数据很大,人口普查员不会复制数据。它只是每隔10秒从馈线观察者那里得到一组指针

为了有必要使用弱指针,让我们说喂食者观察者只提供指向过去十秒内到达的鸟类的指针,而不是那些曾经到过的指针。也就是说,没有通知鸟类已经消失。

通过使用弱指针,它可以在报告时知道哪些鸟仍在那里,何时到达(但不是在他们离开时)。

(也许我稍后会想到一个更好的例子。)

答案 1 :(得分:4)

想象一个假想的计时器事件源的回调函数

struct my_thing : std::enable_shared_from_this<my_thing>
{
  void start()
  {
    auto weak_self = std::weak_ptr<my_thing>(shared_from_this());
    _timer.set_callback([weak_self] {
      if (auto self = weak_self.lock()) {
        self->respond_to_timer();
      }
    });
  }

  void respond_to_timer()
  {
    // do something here
  }

  SomeTimer _timer;
};

在上面的示例中,my_thing拥有计时器,但计时器已经获得了一个引用my_thing的回调。这将是一个循环引用,可以防止my_thing被删除。

使用weak_self weak_ptr打破了循环所有权问题。

答案 2 :(得分:2)

e.g:

struct node
{
   std::shared_ptr<node> left_child;
   std::shared_ptr<node> right_child;
   std::weak_ptr<node> parent;
   foo data;   
};

在此示例中,删除节点将删除left_child和right_child,但不删除父节点。如果由于某种原因,节点比父节点更长,并且父节点被删除,则可以知道父节点不再有效。 (假设您没有引用left_child或right_child与另一个shared_ptr)