为什么std :: unique_ptr operator * throw和operator->不抛? [英] Why does std::unique_ptr operator* throw and operator-> does not throw?
问题描述
在C ++标准草案(N3485)中,它规定如下:
In the C++ standard draft (N3485), it states the following:
20.7.1.2.4 unique_ptr observers [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.
您可以看到 operator *
)没有指定为 noexcept
,可能是因为它可能导致segfault,但是在 operator->
对象被指定为 noexcept
。
You can see that operator*
(dereference) is not specified as noexcept
, probably because it can cause a segfault, but then operator->
on the same object is specified as noexcept
. The requirements for both are the same, however there is a difference in exception specification.
我注意到它们有不同的返回类型,一个返回一个指针,另一个返回一个引用。这是说 operator->
实际上并不取消任何引用吗?
I have noticed they have different return types, one returns a pointer and the other a reference. Is that saying that operator->
doesn't actually dereference anything?
事实是,在任何类型的指针为NULL的情况下使用 operator->
,将segfault(是UB)。为什么,是这些之一指定为 noexcept
,另一个不是?
The fact of the matter is that using operator->
on a pointer of any kind which is NULL, will segfault (is UB). Why then, is one of these specified as noexcept
and the other not?
编辑:
查看 std :: shared_ptr
我们有这样:
20.7.2.2.5 shared_ptr observers [util.smartptr.shared.obs]
20.7.2.2.5 shared_ptr observers [util.smartptr.shared.obs]
T& operator*() const noexcept;
T* operator->() const noexcept;
这不一样?这与不同的所有权语义有什么关系吗?
It's not the same? Does that have anything to do with the different ownership semantics?
推荐答案
segfault不在C ++的异常系统之外。如果你解引用一个空指针,你不会得到任何类型的异常抛出(如果你遵守 Require:
子句,请参见下面的细节)。
A segfault is outside of C++'s exception system. If you dereference a null pointer, you don't get any kind of exception thrown (well, atleast if you comply with the Require:
clause; see below for details).
对于 operator->
,它通常简单地实现 return m_ptr;
(或 return get(); for
unique_ptr
)。正如你所看到的,运算符本身不能抛出 - 它只是返回指针。没有解引用,没有什么。该语言对 p>标识符
有一些特殊规则:
For operator->
, it's typically implemented as simply return m_ptr;
(or return get();
for unique_ptr
). As you can see, the operator itself can't throw - it just returns the pointer. No dereferencing, no nothing. The language has some special rules for p->identifier
:
§13.5。 6 [over.ref] p1
表达式
x-& / code>解释为类对象
x $的
(x.operator->()) - > m
如果T :: operator->()
存在,并且如果选择运算符,则T
作为通过重载解决机制(13.3)的最佳匹配函数。
An expression
x->m
is interpreted as(x.operator->())->m
for a class objectx
of typeT
ifT::operator->()
exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3).
上述应用递归地并且最终必须产生一个指针,其中使用内置的 operator->
。这允许智能指针和迭代器的用户只需做 smart-> fun()
,而不用担心任何事情。
The above applies recursively and in the end must yield a pointer, for which the built-in operator->
is used. This allows users of smart pointers and iterators to simply do smart->fun()
without worrying about anything.
Require:
部分规范的注释:这些表示前提条件。
A note for the Require:
parts of the specification: These denote preconditions. If you don't meet them, you're invoking UB.
为什么呢,其中一个被指定为noexcept,而另一个没有?
Why then, is one of these specified as noexcept and the other not?
说实话,我不确定。看起来,取消引用指针应始终为 noexcept
,但是 unique_ptr
可以完全更改内部指针类型是什么(通过deleter)。现在,作为用户,您可以在指针
类型上为 operator *
定义完全不同的语义。也许它在飞行中计算的东西?所有有趣的东西,可能会抛出。
To be honest, I'm not sure. It would seem that dereferencing a pointer should always be noexcept
, however, unique_ptr
allows you to completely change what the internal pointer type is (through the deleter). Now, as the user, you can define entirely different semantics for operator*
on your pointer
type. Maybe it computes things on the fly? All that fun stuff, which may throw.
查看std :: shared_ptr这个:
Looking at std::shared_ptr we have this:
这很容易解释 - shared_ptr
上述对指针类型的定制,这意味着内置语义始终应用 - 和 * p
其中 p
是 T *
根本不会丢。
This is easy to explain - shared_ptr
doesn't support the above-mentioned customization to the pointer type, which means the built-in semantics always apply - and *p
where p
is T*
simply doesn't throw.
这篇关于为什么std :: unique_ptr operator * throw和operator->不抛?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!