52

I've recently read about [[nodiscard]] in C++17, and as far as I understand it's a new feature (design by contract?) which forces you to use the return value. This makes sense for controversial functions like std::launder (nodiscard since C++20), but I wonder why std::move isn't defined like so in C++17/20. Do you know a good reason or is it because C++20 isn't finalised yet?

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
bbalchev
  • 827
  • 1
  • 9
  • 19
  • 1
    I know a reason that makes sense to me, but unless there's an official document explicitly saying why it isn't, that just turns the question to be opinion-based. – Sebastian Redl Apr 20 '19 at 10:24
  • Why do you think it's not necessary for std::move to be [[nodiscard]]? – bbalchev Apr 20 '19 at 10:28
  • 9
    Because absolutely nothing bad (or at all) happens when you don't use it. – Sebastian Redl Apr 20 '19 at 10:33
  • 6
    @SebastianRedl: similarly, nothing useful happens. It's the same as writing an empty statement, so `[[nodiscard]]` would help diagnose bugs. Also, nothing bad happens when `vector::empty()` is ignored, but that is marked `[[nodiscard]]` for obvious reasons. – Vittorio Romeo Apr 20 '19 at 10:39
  • You could write and submit a proposal paper to add it :) – Jesper Juhl Apr 20 '19 at 12:57
  • 6
    @SebastianRedl That sounds like a great reason _to_ mark it `[[nodiscard]]`: "Hey, you did something completely pointless. Did you mean to do something else?" – Barry Apr 20 '19 at 18:53
  • @SebastianRedl that's not entirely correct though. Objects are said to be in a valid but unspecified state and only assignment operator could be used safely on them. So it's not "nothing bad (or at all) happens" in my opinion. – bbalchev Apr 20 '19 at 19:28
  • 4
    @bbalchev `std::move` doesn't move. Passing an object through `std::move` and ignoring the result does absolutely nothing. – tkausl Apr 20 '19 at 23:04
  • Sure, but you can't use the parameter you gave to `std::move` except for `operator=`, so that's still an error, isn't it? – bbalchev Apr 20 '19 at 23:41
  • @bbalchev A separate `std::move(x);` is a no-op. – L. F. Apr 21 '19 at 05:46
  • 2
    @bbalchev All `std::move` does is return an rvalue reference to the object; so that the object *can* subsequently be moved from *if* the reference is used that way. – Sebastian Redl Apr 21 '19 at 15:52
  • You could make your own `bbalchev::move` which has a `[[nodiscard]]` on it. I'd call mine `eljay::move_dammit`, but that's just me. – Eljay May 03 '19 at 21:55
  • @GertArnold, I did but it is pending review – Alex Guteniev Sep 20 '21 at 05:41

2 Answers2

53

The MSVC standard library team went ahead and added several thousand instances of [[nodiscard]] since VS 2017 15.6, and have reported wild success with it (both in terms of finding lots of bugs and generating no user complaints). The criteria they described were approximately:

  1. Pure observers, e.g. vector::size(), vector::empty, and even std::count_if()
  2. Things that acquire raw resources, e.g. allocate()
  3. Functions where discarding the return value is extremely likely to lead to incorrect code, e.g. std::remove()

MSVC does mark both std::move() and std::forward() as [[nodiscard]] following these criteria.

While it's not officially annotated as such in the standard, it seems to provide clear user benefit and it's more a question of crafting such a paper to mark all the right things [[nodiscard]] (again, several thousand instances from MSVC) and apply them -- it's not complex work per se, but the volume is large. In the meantime, maybe prod your favorite standard library vendor and ask them to [[nodiscard]] lots of stuff?

Barry
  • 286,269
  • 29
  • 621
  • 977
32

AFAIK P0600R1 is the only proposal for adding [[nodiscard]] to the standard library that was applied to C++20. From that paper:

We suggest a conservative approach:

[...]

It should not be added when:

  • [...]
  • not using the return value makes no sense but doesn’t hurt and is usually not an error
  • [...]

So, [[nodiscard]] should not signal bad code if this

  • [...]
  • doesn’t hurt and probably no state change was meant that doesn’t happen

So the reason is that the standard library uses a conservative approach and a more aggresive one is not yet proposed.

cpplearner
  • 13,776
  • 2
  • 47
  • 72
  • 7
    I dunno. Not using the return value of `std::move` is always an error in my book, and should thus be nodiscard according to your citation: it either implies that the user forgot to use the return value, or that the call is unnecessary, since it has no effect. – Konrad Rudolph Apr 20 '19 at 23:21
  • 1
    @KonradRudolph: Nobody has apparently shown the committee a common case in which the lack of nodiscard on `std::move()` causes actual errors. Consider bringing this up in the C++ standard-discuss mailing list. – einpoklum Apr 01 '20 at 21:20
  • 1
    @einpoklum Presumably like others, I don’t consider this issue urgent enough to waste the committee’s time on it (there are already too many new proposals). All I’m saying is that the lack of `[[nodiscard]]` is *probably* an oversight rather than a conscious decision motivated by the quote in this answer. – Konrad Rudolph Apr 02 '20 at 08:13