12

I have watched Scott Meyers' talk on GoingNative2013 "An Effective C++11/14 Sampler" and he explained the use of std::move_if_noexcept.

So in my opinion there should be a std::forward_if_noexcept to also guarantee exception-safety for forward? Why is there nothing like this in the Standard Library? Is there another possibility to guarantee it?

Niall
  • 30,036
  • 10
  • 99
  • 142
  • 1
    There's no point in restoring or preserving an rvalue. That doesn't mean that there aren't use cases for such a helper, though. – dyp Aug 15 '14 at 19:19
  • What would the semantics of `forward_if_noexcept` be? I.e., compared to `move_if_noexcept`? – Niall Aug 15 '14 at 19:22
  • *"to also guarantee exception-safety for `forward`"* I'm not sure I understand what you mean here. `move_if_noexcept` doesn't have any more or less exception safety guarantees than `move`: it's `noexcept`, just a cast. `move_if_noexcept` is useful to preserve objects, i.e. being able to restore a former state if moving can fail. – dyp Aug 15 '14 at 19:24
  • 1
    Niall, forward is able to handle universal references, so with the collapsing rules, if i use a Templatefunction with Typededuction and T&&, and i call it with a rvalue -> it will move, if i call it with a lvalue -> it will copy. So in my opinion forward_if_noexcept should extend forward to copy if theres no noexcept, else the old behavior. – Benjamin Schmidt Aug 15 '14 at 19:29
  • @BenjaminSchmidt, interesting question and rationale. – Niall Aug 15 '14 at 19:48
  • @dyp what i meant by a guarantee of exception-safety is strong exception safety (see http://en.wikipedia.org/wiki/Exception_safety) so if a couple of moves fail at some point (exception), you cannot roll back to the initial state of data. This safety is given by `move_if_noexcept`, because it checks if the Type of object is noexcept(true). If it's true -> move is safe and will be performed, if it's false -> copy will be performed to guarantee a rollback – Benjamin Schmidt Aug 16 '14 at 17:53
  • @BenjaminSchmidt Ok, then my first comment applies: it's not as useful to restore the state of an rvalue as it is to restore the state of an lvalue (one might even argue that it's not useful at all). – dyp Aug 16 '14 at 21:02

1 Answers1

7

The forward semantics already are conditional, i.e., they preserve the value category of its argument. The move, on the other hand, unconditionally changes (from an l-value to r-value) the value category of its argument to an r-value (reference), the std::move_if_noexcept obtains the resultant value category based on whether or not the move constructor throws no exceptions, effectively also making it conditional.

In short, std::forward doesn't change anything, it preserves the value category. std::move on the other hand, does change the value category. So std::move_if_noexcept is introduced to say that if std::move's change could cause an exception, then don't change anything; don't move it.

I think the rationale here also goes to the intended idiomatic use of all things std::move and std::forward respectively. In one of Scott's other talks (possibly at C++ and Beyond 2012) on "universal references", forwarding and moving, he was quite emphatic on the idiomatic use of forward, and I think this underpins a lot of what std::forward is and how it is used. It may also just be as simple as it was never considered.

I would argue that there is no need, or at least there is diminished need when the std::forward is effected.

Given that there may be a use case for it, implementing one would not be too hard; but I'm not sure as to the general use case. It could be argued that the conditions related to the possible exceptions, and the required exception guarantees, should be tested for and dealt with outside of the function doing the forwarding.

template <class U, class T>
U wrapper(T&& arg)
{
    return U(forward<T>(arg));
}

template <class U, class T>
U method() 
{
  T t;
  // work with t
  return wrapper<U>(move_if_noexcept(t));
}

Granted, it is "early days" for a lot of this, so that may change.

Niall
  • 30,036
  • 10
  • 99
  • 142
  • correct me if i'm false, but the condition of `std::forward` doesn't check for `noexcept`, so i thought it would call `std::move` if the param is a rvalue, and so there's no preservation? – Benjamin Schmidt Aug 15 '14 at 20:05
  • @BenjaminSchmidt, I'm not aware of any checks wrt `noexcept`, but `forward` doesn't actually call `move`, it's just a `static_cast` (as `move` is) with some error checks on the arguments and types – Niall Aug 15 '14 at 20:13
  • you're right, i used the "call of move" just as an methodology to visualize what happens when forward is called, the actual implementation is different and surely more efficient – Benjamin Schmidt Aug 15 '14 at 20:20
  • @BenjaminSchmidt, I can't remember if it was that talk or another one Scott have on forwarding and moving, but he was quite emphatic on the idiomatic use of forward, and I think this underpins a lot of what forward is and is used how it is. – Niall Aug 15 '14 at 20:24
  • i think this was in C++ and Beyond 2012, i refer to http://channel9.msdn.com/Events/GoingNative/2013/An-Effective-Cpp11-14-Sampler at 19:52 he explained the behavior of `std::forward` with a piece of example code ( like me with a call of move :o) ) – Benjamin Schmidt Aug 15 '14 at 20:28