I have the following code:
void check_portvalue(std::string_view value)
{
[[maybe_unused]] port_t test {value};
}
The object test
remains unused, but creation serves as a check, because the constructor can throw.
The [[maybe_unused]]
attribute suppresses the compiler warning.
But since the compiler detects that this is unused, could it optimize out the entire statement and thus prevent the exception from being thrown ?
I have the following code:
void check_portvalue(std::string_view value)
{
[[maybe_unused]] port_t test {value};
}
The object test
remains unused, but creation serves as a check, because the constructor can throw.
The [[maybe_unused]]
attribute suppresses the compiler warning.
But since the compiler detects that this is unused, could it optimize out the entire statement and thus prevent the exception from being thrown ?
Share Improve this question edited Feb 6 at 16:28 Tootsie asked Feb 6 at 12:52 TootsieTootsie 8674 silver badges12 bronze badges 5 |2 Answers
Reset to default 9Optimizer has to follow the as-if rule (i.e cannot change "observable behaviors")
The only exception to the as-if rule are:
- Copy elision
- the compiler may remove calls to the replaceable allocation functions.
Your code doesn't fall into those categories.
No optimization can remove the call of the constructor in your example. Your example should not actually trigger the warning even without [[maybe_unused]
. Moreover, when the function does nothing but create the object you could as well use an unnamed temporary port_t{value};
to the same effect.
The rest of the answer tries to explain this in details.
Consider this example:
#include <iostream>
struct foo {
foo() { std::cout << "hello"; }
~foo() { std::cout << "bye";}
};
void bar() {
foo f = foo();
std::cout << " x ";
}
int main() { bar(); }
Compling this with warnings enabled (gcc: -Werror -Wall
) produces no warnings and the output is (https://godbolt.org/z/TnoPMWbcs):
hello x bye
Actually this RAII (resource allocation is acquisition) pattern is so common in C++ that compilers can easily spot it and will not issue a warning for the unused variable. The "use" of the variable, is to keep the object alive until the end of the scope to have bye
appear last. No optimization is allowed to change the order of output or cause output to not appear at all. Generally optimziations do not alter the observable behavior of a program (with few exceptions not relevant here).
RAII out of the way, lets consider a different example that does trigger the warning (again -Wall -Werror
):
#include <iostream>
int fee() {
std::cout << "hellobye";
return 42;
};
void ber() {
int f = fee();
std::cout << " x ";
}
int main() { ber(); }
Output of gcc (https://godbolt.org/z/f47Pcsao5):
<source>: In function 'void ber()':
<source>:9:9: error: unused variable 'f' [-Werror=unused-variable]
9 | int f = fee();
| ^
It is just a warning, that we can
- just ignore (https://godbolt.org/z/Mhs8d3qnb)
- silence via
[[maybe_unused]]
(https://godbolt.org/z/qM3dK4jbn) - fix by simply not declaring a variable (https://godbolt.org/z/693nqffz6)
In any case the output from calling the function must appear.
Regarding the warning, note that generally warnings are not mandated by the standard. Even [[maybe_unused]]
is merely a recommendation to compilers. A compiler can ignore the attribute and still be standard conforming.
Imagine the author considered fee
a poor name for what the function does in context of ber
. They choose to give a much better name f
. Imagine further, that they do not want to ignore the warning. Prior to C++17 one had to resort to hacks to silence the warning. With [[maybe_unused]]
one has no longer resort to hacks. A future reader does not have to rely on warnings. A variable declared as [[maybe_unsued]]
does not need browsing of potentially many lines of code to see that is not used but was given a name on purpose.
check_portvalue
function instead of being passed on to theport_t
constructor? Or perhaps it could be astatic
member function ofport_t
, andcheck_portvalue
is just a proxy for that? – Some programmer dude Commented Feb 6 at 12:59port_t{value};
to avoid[[maybe_unused]]
. – Jarod42 Commented Feb 6 at 13:20(void) port_t{value};
maybe? – YSC Commented Feb 6 at 13:50port_t
constructor itself could call the freestanding function.) – Eljay Commented Feb 6 at 14:13