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
那里p
是T*
根本不会抛出.