c++attributesc++17nodiscard

What is the rationale behind having [[nodiscard]] types?


What are usecases in which it is beneficial to use a [[nodiscard]] type?

On types, [[nodiscard]] emits a warning if the return value of any function returning an instance of that type is omitted; (Citation from p0068r0):

If [[nodiscard]] is marked on a type, it makes it so that all functions that return that type are implicitly [[nodiscard]].

while a [[nodiscard]] constructor (c++2a) is very useful for classes which manage resources (e.g. unique_ptr) and nodiscard for functions are for instance useful for make_unique I cannot come up with an example where a nodiscard for a type is useful and I'm interested in cases where it is used.


Solution

  • Consider the type std::unique_lock<M>. It's an obvious candidate for marking the constructor (specifically the one that takes M&) nodiscard, as we would not want to write some code like this by accident:

    std::unique_lock<M>(m);
    // oops! we actually meant
    // std::unique_lock<M> lck(m);
    

    This falls under the "manages resources" category.

    But this is also an example of a type that we would not want to have discarded if returned from a function:

    std::unique_lock<M> getLockFor(Arg x) {
        std::unique_lock<M> result;
        // acquire some lock based on x
        return result;
    }
    
    {
        auto lck = getLockFor(arg1);  // ok
        // do some stuff that requires the lock to be held
    }
    {
        getLockFor(arg2);  // warning!
        // lock will NOT be held here!
    }
    

    To get the warning in this case, we would need to mark the type as nodiscard, not just the constructor.

    I think, in fact, this example illustrates that perhaps most classes that manage resources should be nodiscard, as it is probably a bug when we call a function that returns to us control over a resource, merely to release that resource immediately by not using the return value.