BDE 4.14.0 Production release
|
Macros | |
#define | BSLA_NODISCARD |
#define | BSLA_NODISCARD_CPP17 |
Provide a macro for warning about ignored function results.
BSLA_NODISCARD
is active[[nodiscard]]
if availableBSLA_NODISCARD_CPP17
is activeThis component provides two preprocessor macros that annotate entities that should not be ignored. Widely supported is annotating a function such that a compiler warning will be generated if the return value of the function is ignored, which is what BSLA_NODISCARD
does. C++17 and later compilers also support annotating types, BSLA_NODISCARD_CPP17
is defined when such annotation is supported.
BSLA_NODISCARD
: This annotation causes a warning to be emitted if the caller of a so-annotated function does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug, such as with the realloc
function. The annotation cannot be used portably on constructors if C++03 support is required because the GNU compiler reuses their C (language) implementation for compatibility and that does not understand that constructors. Attempt to apply BSLA_NODISCARD
to a constructor will result in a warning from gcc:
BSLA_NODISCARD_IS_ACTIVE
: The macro BSLA_NODISCARD_IS_ACTIVE
is defined if BSLA_NODISCARD
expands to something with the desired effect; otherwise BSLA_NODISCARD_IS_ACTIVE
is not defined and BSLA_NODISCARD
expands to nothing.
BSLA_NODISCARD_CPP17
: This annotation can be used on both types and functions. Due to differences in compiler parser implementations this macro must be placed after the class
(or struct
) keyword and before the name of the type; otherwise it might not compile.
[[ nodiscard ]]
instead of the whole type, so it is easy to avoid portability issues by marking the type itself nodiscard.BSLA_NODISCARD_CPP17
in effect makes any function (including constructors) that return such a type by value or create an object of that type (in case of constructors) behave as if they were all (individually) marked by BSLA_NODISCARD_CPP17
. This ability is very useful for guards or any other RAII types where using the object as part of a discarded-value expression has completely different behavior than using a (named) variable of it. BSLA_NODISCARD_CPP17_IS_ACTIVE
: The macro BSLA_NODISCARD_CPP17_IS_ACTIVE
is defined if BSLA_NODISCARD_CPP17
expands to something with the desired effect; otherwise BSLA_NODISCARD_CPP17_IS_ACTIVE
is not defined and BSLA_NODISCARD_CPP17
expands to nothing.This section illustrates intended use of this component.
First, we define a function, newtonsSqrt
, which uses Newton's method for calculating a square root. Since the function has no side effects, it doesn't make sense to call it and ignore its result, so we annotate it with BSLA_NODISCARD
:
Then, in main
, we call it normally a few times and observe that it works with no compiler warnings generated:
Next, we call it and do nothing with the result, which will generate a warning:
Now, we call it and explicitly void the result, which, with gcc, still won't suppress the "unused result" warning:
Finally, we observe the compiler warnings from the last 2 calls:
Suppose we create a guard type that is capable of closing delimiters that we have opened while operating on an output stream. The example uses C I/O and string literals for brevity.
First, we define a guard type DelimiterGuard0
:
Then we can write code that uses the guard properly:
Next, we demonstrate that the guard works as intended:
Then, we write code missing the variable name for the guard. By not giving a variable name we turn what should be an automatic (local) variable definition into a so-called expression statement: <expression>;
. Expression statements execute an expression for its side effects, then destroy all temporaries created in the expression "at the semicolon". All the printf
function calls below are expression statements, they just don't have any temporaries to destroy.
Next, we demonstrate the bug cause by the guard variable name missing:
Then, we add the no-discard annotation to our guard type directly:
The rest is omitted for brevity.
Next, we can write the buggy code again using the annotated type:
Finally, we can demonstrate using a C++17 compiler that we get a warning for the buggy code:
#define BSLA_NODISCARD |
#define BSLA_NODISCARD_CPP17 |