The following program compiles without warnings with -O0
:
#include <iostream>
struct Foo
{
int const& x_;
inline operator bool() const { return true; }
Foo(int const& x):x_{x} { }
Foo(Foo const&) = delete;
Foo& operator=(Foo const&) = delete;
};
int main()
{
if (Foo const& foo = Foo(3))
std::cout << foo.x_ << std::endl;
return 0;
}
However with -O1
or higher it gives the warning:
maybe-uninitialized.cpp: In function ‘int main()’:
maybe-uninitialized.cpp:15:22: warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
std::cout << foo.x_ << std::endl;
How do you get rid of this warning with -O1
and higher?
The motivation for this is for a CHECK(x)
macro which must capture a const reference rather than a value so as not to trigger a destructor, copy constructor, etc. as well as print out a value.
Resolution is at the bottom
Edit:
$ g++ --version
g++ (GCC) 8.2.1 20181127
No warnings: g++ maybe-uninitialized.cpp -Wall -O0
With warning: g++ maybe-uninitialized.cpp -Wall -O1
Edit 2 in response to @Brian
#include <iostream>
struct CheckEq
{
int const& x_;
int const& y_;
bool const result_;
inline operator bool() const { return !result_; }
CheckEq(int const& x, int const &y):x_{x},y_{y},result_{x_ == y_} { }
CheckEq(CheckEq const&) = delete;
CheckEq& operator=(CheckEq const&) = delete;
};
#define CHECK_EQ(x, y) if (CheckEq const& check_eq = CheckEq(x,y)) \
std::cout << #x << " != " << #y \
<< " (" << check_eq.x_ << " != " << check_eq.y_ << ") "
int main()
{
CHECK_EQ(3,4) << '\n';
return 0;
}
The above is more interesting in that there are no warnings, but different output depending on the -O0
or -O1
:
g++ maybe-uninitialized.cpp -O0 ; ./a.out
Output: 3 != 4 (3 != 4)
g++ maybe-uninitialized.cpp -O1 ; ./a.out
Output: 3 != 4 (0 != 0)
Edit 3 - Accepted answer
Thanks to @RyanHaining.
#include <iostream>
struct CheckEq
{
int const& x_;
int const& y_;
explicit operator bool() const { return !(x_ == y_); }
};
int f() {
std::cout << "f() called." << std::endl;
return 3;
}
int g() {
std::cout << "g() called." << std::endl;
return 4;
}
#define CHECK_EQ(x, y) if (CheckEq const& check_eq = CheckEq{(x),(y)}) \
std::cout << #x << " != " << #y \
<< " (" << check_eq.x_ << " != " << check_eq.y_ << ") "
int main() {
CHECK_EQ(f(),g()) << '\n';
}
Output:
f() called.
g() called.
f() != g() (3 != 4)
Features:
- Each parameter to
CHECK_EQ
is only checked once. - Output displays inline code comparison as well as values.