为什么std :: unique_ptr operator*throw和operator->不抛出?

Ton*_*ion 34 c++ language-lawyer c++11

在C++标准草案(N3485)中,它声明如下:

20.7.1.2.4 unique_ptr观察者[unique.ptr.single.observers]

typename add_lvalue_reference<T>::type operator*() const;

1 Requires: get() != nullptr.
2 Returns: *get().

pointer operator->() const noexcept;

3 Requires: get() != nullptr.
4 Returns: get().
5 Note: use typically requires that T be a complete type.
Run Code Online (Sandbox Code Playgroud)

您可以看到operator*(取消引用)未指定为noexcept,可能是因为它可能导致段错误,但随后operator->在同一对象上指定为noexcept.两者的要求相同,但异常规范存在差异.

我注意到它们有不同的返回类型,一个返回一个指针,另一个返回一个引用.这是说operator->实际上没有取消引用任何东西吗?

事实是在operator->任何类型的指针上使用NULL,将是段错误(是UB).那么,为什么其中一个被指定为noexcept另一个而不是?

我确定我忽视了一些事情.

编辑:

看着std::shared_ptr我们有这个:

20.7.2.2.5 shared_ptr观察者[util.smartptr.shared.obs]

T& operator*() const noexcept;

T* operator->() const noexcept;
Run Code Online (Sandbox Code Playgroud)

这是不一样的?这与不同的所有权语义有什么关系吗?

Xeo*_*Xeo 26

段错误不在C++的异常系统中.如果取消引用空指针,则不会抛出任何类型的异常(嗯,至少如果您遵守该Require:条款;请参阅下面的详细信息).

因为operator->,它通常简单地return m_ptr;(或return get();unique_ptr)实现.如您所见,操作符本身不能抛出 - 它只返回指针.没有解除引用,没有任何东西.该语言有一些特殊规则p->identifier:

§13.5.6 [over.ref] p1

表达式x->m被解释为类型为if (x.operator->())->m的类对象x,T如果T::operator->()操作符被重载决策机制选为最佳匹配函数(13.3).

以上适用于递归,最后必须产生一个指针,使用内置指针operator->.这允许智能指针和迭代器的用户完全smart->fun()不用担心任何事情.

说明Require:部分的注释:这些表示前提条件.如果你不满足他们,你就是在调用UB.

那么,为什么其中一个指定为noexcept而另一个不指定?

说实话,我不确定.这似乎是解引用指针应始终noexcept,然而,unique_ptr让您彻底改变内部指针类型是(通过删除器)的东西.现在,作为用户,您可以为operator*您的pointer类型定义完全不同的语义.也许它会在飞行中计算出来的东西?所有有趣的东西,可能会抛出.


看看std :: shared_ptr我们有这个:

这很容易解释- shared_ptr不支持上述定制指针类型,这意味着内置的语义总是适用-和*p那里pT*根本不会抛出.

  • +1为"operator*"的自定义语义的可能性. (4认同)
  • 抛出unique_ptr dereference的一个用例是一个自定义指针类型,它抛出null dereference. (3认同)
  • @Stephen:`D`是删除类型,如果定义了嵌套的`指针`类型,则使用该类型. (2认同)