9

While implementing a basic std library for my hobby OS I came across this and wondered why:

Both operator->() and T* get() are marked as noexcept, however operator*() is not. According to the reference it should be equivalent to *get(), which would allow it to be noexcept and looking at some implementations I see no reason why it is not.

Why is unique_ptr's dereferencing operator not marked as noexcept?

Quentin
  • 62,093
  • 7
  • 131
  • 191
Thalhammer
  • 285
  • 3
  • 7
  • I am voting to close this issue because it is an error merely based off trusting [cplusplus](http://cplusplus.com/) and cannot be reproduced on other sources. – Yakk - Adam Nevraumont Feb 01 '18 at 16:52

2 Answers2

8

Because operator* for the pointer type of std::unique_ptr may throw. The pointer type alias is defined as:

std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*. Must satisfy NullablePointer

That may be something other that T*, it may be a class type that overloads operator*.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I'm just wondering whether it's a good practice to mark `->` `noexcept` in such case. Technically it is indeed `noexcept`, but actually the throw is delayed to the dereference of the returned object. A simple expression `a->b` *might* throw. It will cause some confusion. – llllllllll Feb 01 '18 at 12:52
  • @liliscent - Yes the expression may throw, but it's not unique_ptr's overload where the exception escapes from. The specifier is appropriate, since the function is non throwing, even if the expression potentially is – StoryTeller - Unslander Monica Feb 01 '18 at 12:58
6

From cppreference

  • typename std::add_lvalue_reference<T>::type operator*() const; (1) (since C++11)
  • pointer operator->() const noexcept; (2) (since C++11)

And then:

Exceptions:
1) may throw, e.g. if pointer defines a throwing operator*

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thanks, I was using cplusplus.com which didn't include information about throwing. – Thalhammer Feb 01 '18 at 10:58
  • 1
    But why isn't it conditionally `noexcept` either? Almost all of the time, a plain pointer will be used, and in this case `*foo.get()` is `noexcept`, but `*foo` is not. I know it matters little in practice because all of these will be `inline` anyway. – Arne Vogel Feb 01 '18 at 11:57
  • This precision is not actually in the standard, but I think this is what is intended. – Quentin Feb 01 '18 at 12:26
  • 2
    @ArneVogel - See [LWG Issue 2762](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2762). – StoryTeller - Unslander Monica Feb 01 '18 at 12:34