My boys! We love testing, don't we? More #cpp / #cxx questions for you to sharpen your wits and train your legalese on. Because when it comes to regulations, it's important to not leave anything to chance, even more now that the military says they want to loooooove C++ (in a "why can't you be like Rust?" way).
So:
How to make sure the caller of your function does not ignore the result?
[ ] Mark the function as "[[nodiscard]]", as attributes are totally mandatory
[ ] Return the result as an exception, via "throw result;"
[ ] Add a // comment explaining to not ignore, and let the client's IDE do the rest
[ ] Return the result via an out-parameter, so the user has no option but to be aware of it
When would this actually be necessary? Realistically, I see two possibilities.
1 - The function’s purpose is to generate a result value, meaning that ignoring the result is a waste of a function call and any resources consumed by the function. In this case, though, nobody would ever be calling the function unless they specifically wanted the result.
2 - The caller must take ownership of the result. In this case, just don’t return raw pointers.
The addition of [[nodiscard]] suggests that there are valid reasons, but I have never personally come across one.
Consider, say, the printf family of functions. The side-effect of their invocation is quite notorious and clear: print something to the screen, or write it to a file, etc. This kind of thing is not expressable (and should not be expressed as) as a return type. But these functions do have a return value: a status code indicating whether the write-to-medium was successful or else why. It’s so easy to discard this information and end up eg.: ignorin a write that didn’t happen because there was not enough room, or writing more bytes than the destination buffer could afford to take (hellooooo, buffer overflow!).
There are lots of functions (probably entire categories, but I’m not that strong on type theory) where the “result” is vastly different from the “return” or can not be expressed as such. Foremost cases I can come up with are I/O, stuff on complex types where types also represent actions or components with side effects (eg.: GUIs), and pretty much anything about inserting or removing elements from containers. In those cases, if the two things differ but the return is also important, it’d be nice to have a mechanism to make sure that it can’t be accidentally ignored (explicit, intentional ignoring is fine; that’s what we have (void)(expr...) in the language).
Another reason for having this capability is having a function with a composite return-result type, such as a std::expected<T,E> where you want to help make sure the composition is handled correctly by the caller.
When would this actually be necessary? Realistically, I see two possibilities.
1 - The function’s purpose is to generate a result value, meaning that ignoring the result is a waste of a function call and any resources consumed by the function. In this case, though, nobody would ever be calling the function unless they specifically wanted the result.
2 - The caller must take ownership of the result. In this case, just don’t return raw pointers.
The addition of [[nodiscard]] suggests that there are valid reasons, but I have never personally come across one.
Consider, say, the
printf
family of functions. The side-effect of their invocation is quite notorious and clear: print something to the screen, or write it to a file, etc. This kind of thing is not expressable (and should not be expressed as) as a return type. But these functions do have a return value: a status code indicating whether the write-to-medium was successful or else why. It’s so easy to discard this information and end up eg.: ignorin a write that didn’t happen because there was not enough room, or writing more bytes than the destination buffer could afford to take (hellooooo, buffer overflow!).There are lots of functions (probably entire categories, but I’m not that strong on type theory) where the “result” is vastly different from the “return” or can not be expressed as such. Foremost cases I can come up with are I/O, stuff on complex types where types also represent actions or components with side effects (eg.: GUIs), and pretty much anything about inserting or removing elements from containers. In those cases, if the two things differ but the return is also important, it’d be nice to have a mechanism to make sure that it can’t be accidentally ignored (explicit, intentional ignoring is fine; that’s what we have
(void)(expr...)
in the language).Another reason for having this capability is having a function with a composite return-result type, such as a
std::expected<T,E>
where you want to help make sure the composition is handled correctly by the caller.