Attributes¶
[[noreturn]]
¶
Function attribute
Compiler can know that control flow will not return to the caller
⟶ warnings
⟶ optimizations
#include <stdlib.h>
[[noreturn]] void terminate()
{
exit(0);
}
int foo()
{
terminate();
return 42; // <-- *could* be warned
}
int main()
{
return foo();
}
GCC 13 does not say anything though
[[deprecated]]
¶
[[deprecated]] void old_crap()
{
// ...
}
[[deprecated("this is crap")]] void old_crap2()
{
// ...
}
int main()
{
old_crap(); // <-- warning: ‘void old_crap()’ is deprecated
old_crap2(); // <-- warning: ‘void old_crap2()’ is deprecated: this is crap
return 0;
}
[[fallthrough]]
: Problem¶
GCC:
-Wimplicit-fallthrough
is highly recommended (also enabled by-Wextra
)Omitting
break
is usually a bugSimilar functionality available from other compilers too
(GCC?) observation: have to have a statement before falling through
#include <cstdlib>
#include <ctime>
#include <iostream>
int main()
{
std::srand(std::time(nullptr));
int number = std::rand();
bool seen_zero = false;
switch (number) {
case 0:
seen_zero = true; // <-- warning: this statement may fall through
case 1:
std::cout << "uh, this was unlikely\n";
break;
}
if (seen_zero)
std::cout << "uh, this was even more unlikely\n";
return 0;
}
Sometimes
break
-lesscase
is desired⟶ Want to selectively disable
[[fallthrough]]
: Usage¶
#include <cstdlib>
#include <ctime>
#include <iostream>
int main()
{
std::srand(std::time(nullptr));
int number = std::rand();
bool seen_zero = false;
switch (number) {
case 0:
seen_zero = true;
[[fallthrough]]; // <-- suppress warning
case 1:
std::cout << "uh, this was unlikely\n";
break;
}
if (seen_zero)
std::cout << "uh, this was even more unlikely\n";
return 0;
}
[[nodiscard]]
: Problem¶
Compiler does not insist that function return values are respected
There might be warning options, but these are probably too loud (and unwanted in most cases)
bool might_fail()
{
return false;
}
int main()
{
might_fail(); // <-- potential error not handled
return 0; // <-- ... though exit OK
}
[[nodiscard]]
: Solution¶
[[nodiscard]]
, best together with-Werror
⟶ Usage has to be fixed
[[nodiscard]] bool might_fail()
{
return false;
}
int main()
{
might_fail(); // <-- warning: ignoring return value of ‘bool might_fail()’, declared with attribute ‘nodiscard’
return 0;
}
⟶ fix it
[[nodiscard]] bool might_fail()
{
return false;
}
int main()
{
bool ok = might_fail();
return ok?0:1;
}
[[nodiscard]]
On Entire Types¶
enum class [[nodiscard]] Error
{
OK,
FAILED,
NONSENSE,
// ...
};
Error might_fail()
{
return Error::FAILED;
}
int main()
{
Error e = might_fail();
return (e == Error::OK)?0:1;
}
[[maybe_unused]]
¶
Compiler warns about unused variables (
-Wunused-variable
,-Wall
)Hard to find a usecase where this is not wanted
I don’t believe there is one
int main()
{
int unused_variable;
return 0;
}
int main()
{
[[maybe_unused]] int unused_variable;
return 0;
}
[[likely]]
¶
Help the compiler with branch optimization
Attention though (see here): there may be a performance penalty for misguessing
That said …
#include <string>
int main(int, const char* const* argv)
{
int num = std::stoi(argv[1]);
if (num < 42) [[likely]]
return 0;
else [[unlikely]]
return 1;
}
#include <string>
int main(int, const char* const* argv)
{
int num = std::stoi(argv[1]);
switch (num) {
case 1: [[fallthrough]];
case 2: [[fallthrough]];
case 3: [[fallthrough]];
// ...
// even though 1..41 fall through to 42, they aren't as
// likely as 42
// ...
case 41: [[fallthrough]];
[[likely]] case 42:
return 0;
default:
return 1;
}
}