【问题标题】:Why doesn't std::weak_ptr have operator->?为什么 std::weak_ptr 没有 operator->?
【发布时间】:2015-03-14 06:10:48
【问题描述】:

可以这样实现:

  std::shared_ptr<T> operator->() {
      auto shared = lock();
      if(shared == nullptr) {
          throw std::bad_weak_ptr(); // or some other exception
      }
      return shared;
  }

Live Demo

为什么weak_ptr的作者决定不使用operator->?(他们一定想到了)

我能想到潜在的原因,但我想知道官方原因是什么,如果存在的话。潜在原因:

  • 不鼓励对多次调用额外增加/减少引用计数
  • 鼓励显式锁定而不是(有些隐藏的)异常

如果您对返回的 shared_ptr 的生命周期感到困惑,请参阅this paper.

另外,有人问如果你希望它不会过期,为什么要使用weak_ptr?答案:循环。

【问题讨论】:

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


    【解决方案1】:

    original proposal weak_ptr 不包含 operator-&gt; 的重载。

    从那以后,我没有看过每次会议的记录,但一直在关注讨论的内容,并且不记得有人提到应该添加它。因此,它不存在的“官方”原因可能主要是没有人提议添加它。

    如果你想回到非常的开头,大部分内容来自 John Ellis 和 David Detlef 的 Safe, Efficient Garbage Collection for C++ 论文,来自 Usenix 1994。其中包括在其附录中的 weakptr 类型B. 这有点不同(weakptr::pointer 直接返回一个指针,如果指针已经被销毁,则返回一个空指针),但仍然没有使用运算符重载来完成这项工作。

    Greg Colvin 将original proposal to add counted_ptr 写入标准。它的counted_ptr 基本上等同于现在的shared_ptr,但不包含任何类似于weak_ptr 的内容。

    在委员会否决了counted_ptr 提案并转而采用auto_ptr 后不久,counted_ptr 的基本思想在 Boost 上得到了复兴。我不记得看到任何关于向其添加operator-&gt; 的讨论,但它在那里“生活”了很长时间,以至于完全有可能有人在我不知道的情况下提出了它。

    【讨论】:

    • 但据我所知,提议的operator-&gt; 完全符合您的描述:转换为shared_ptr,并且仅在成功时才允许访问该对象(否则抛出)。这怎么会是坏事?
    • @MikeSeymour:您希望保留 shared_ptr 并在其上调用方法,而无需支付同步成本。
    • @AlexandreC.:有时你会这样做,在这种情况下手动转换仍然可用。有时您只想访问单个成员,在这种情况下,手动转换只是噪音,建议的运算符可以使其更整洁。
    • even further back weak_ptr 最古老的 boost 文档我很容易找到:2003 年 2 月 10 日。这里也没有 operator-&gt;。文案声明包括“版权所有 1999 Greg Colvin 和 Beman Dawes。版权所有 2002 Darin Adler。版权所有 2002, 2003 Peter Dimov”与您链接的原始提案的作者一致。 here 是旧文档的片段,1999 年提到了智能指针。 Version 1.20可以指教吗?
    • 啊,boost 1.20版本有共享指针,但乍一看没有弱指针。所以我们可以找到第一个添加弱指针来提升的版本。以上证明std::shared_ptr来自boost(提案的作者和论文本身)。
    【解决方案2】:

    我会尝试给出一个很好的理由说明为什么这不是一个好主意:

    一件事是清晰:

    ptr->foo();
    ptr->bar();
    

    这里的问题是,在第一次和第二次调用之间的某个地方,ptr 可能会因不同的线程(这将是一种竞争条件)或调用foo 的副作用而过期。

    另一件事是对称性:当我有一个指针时,我期望运算符 *-&gt; 和隐式转换为布尔值。有些人可能不同意,但运营商*-&gt; 通常是一致的。我很惊讶这里不是这种情况。

    也就是说,使用 C++11,编写起来太容易了:

    if (auto p = ptr.lock()) {
        p->foo();
        p->bar();
    }
    

    知道ptrweak_ptr,该代码的含义和行为就很清楚了。

    【讨论】:

    • 在询问了更多之后,我认为您对对称性的看法是正确的。当缺少最基本的 operator* 时,拥有 operator-> 会使 weak_ptr 看起来更像一个实际的指针。
    • 我也想到这是一个很好的理由。简而言之,weak_ptr 不是一个指针,所以它不应该表现得像一个指针。或许weak_ref 会是更好的选择,但也采用了术语引用。
    猜你喜欢
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 2018-08-13
    • 2021-01-02
    相关资源
    最近更新 更多