0

I'm referring to this question. To make it easier to grasp it, I should note that the mentioned booked C++ Primer tells the readers to implement move-operations - if possible - in a way that no exceptions can be thrown and specifying the keyword noexcept if so. This leads to a set of four declarations of the copy- and move operations:

HasPtr(const HasPtr& hp)
HashPtr& operator=(const HasPtr& rhs)
HasPtr(HasPtr&& hp) noexcept
HashPtr& operator=(HasPtr&& rhs) noexcept

Or, if we apply the copy-and-swap idiom:

HasPtr(HasPtr& hp)
HasPtr& operator=(HasPtr rhs) // non-reference parameter, copy-and-swap-assigment operator, either calls copy- or move-constructor
HasPtr(HasPtr&& hp) noexcept

Like the book and the original question, I'm interested in the consequences of low-level efficiency:

In the case of HasPtr we need to allocate memory if the copy-assignment constructor receives a lvalue as parameter and allocating memory can throw a bad_alloc exception (if not nothrow is used). So we shall not add noexcept to the copy-assignment operator! Regarding the original question, I assume that the compiler cannot preserve some extra work for possible stack-unwinding of the copy-assignment constructor. Is this correct?

The standard library uses move_if_noexcept which returns an rvalue the move-constructor doesn't throw exceptions. So I assume no drawbacks, because the move-constructor specifies noexcept. Is this correct?

The only remaining thing is this post from Scott Meyers, he mentions the loss of control, when destruction happens and extra pointer copies.

Thank you

PS: Honestly. I wasn't able to add this a comment to the original question, because it is to big in size of characters. I tried to add a similar post as answer and ask if I'm right with my assumptions. People didn't liked that. So I open a new question.

Peter
  • 2,240
  • 3
  • 23
  • 37
  • Maybe add what version you want to inquire about. – Hatted Rooster Sep 14 '18 at 17:14
  • You're right. I added a note, that this generally about low-level efficiency. – Peter Sep 14 '18 at 17:19
  • 2
    `HasPtr& operator=(HasPtr rhs)` can be `noexcept` as the memory is allocated in the context of the caller. In the function `rhs` can be safely moved from. – Richard Critten Sep 14 '18 at 17:20
  • @RichardCritten: Thank you. I thought in the context of the called function. Then the authors probably just doesn't specifiy `noexcept`, because there is not a such a big benefit like for the move-operations. – Peter Sep 14 '18 at 17:26
  • "*I assume that the compiler cannot preserve some extra work for possible stack-unwinding of the copy-assignment constructor*" - what do you mean exactly? – Remy Lebeau Sep 14 '18 at 17:27
  • "*this post from Scott Meyers, he mentions the loss of control, when destruction happens and extra pointer copies*" - only when swapping old data into the object being moved from, if that object outlives the assignment. Which is possible in `HashPtr& operator=(HasPtr&& rhs)`, and Scott covers that. You can mitigate that by moving the new data into a local variable that you then swap with the target, thus the old data gets freed when the variable goes out of scope when the assignment operator exits. Scott didn't cover that, but `HasPtr& operator=(HasPtr rhs)` handles that implicitly for you. – Remy Lebeau Sep 14 '18 at 17:30
  • @Remy Lebeau: Exceptions and unwinding generally can cost "some" performance. Quote: *Note that a noexcept specification on a function is not a compile-time check; it is merely a method for a programmer to inform the compiler whether or not a function should throw exceptions. The compiler can use this information to enable certain optimizations on non-throwing functions as well as enable the noexcept operator, which can check at compile time if a particular expression is declared to throw any exceptions.* en.cppreference.com/w/cpp/language/noexcept_spec – Peter Sep 14 '18 at 17:44

0 Answers0