【问题标题】:warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]警告:“<anonymous>”在此函数中未初始化 [-Wuninitialized]
【发布时间】:2019-05-03 20:04:43
【问题描述】:

以下程序编译时没有警告-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;
}

但是-O1 或更高版本会发出警告:

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;

如何使用-O1 及更高版本消除此警告?

这样做的动机是 CHECK(x) 宏必须捕获 const 引用而不是值,以免触发析构函数、复制构造函数等以及打印出值。

分辨率在底部

编辑:

$ g++ --version
g++ (GCC) 8.2.1 20181127

No warnings:  g++ maybe-uninitialized.cpp -Wall -O0
With warning: g++ maybe-uninitialized.cpp -Wall -O1

编辑 2 以回应 @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;
}

上面更有趣的是没有警告,但根据-O0-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) 

编辑 3 - 接受的答案

感谢@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';
}

输出:

f() called.
g() called.
f() != g() (3 != 4) 

特点:

  • CHECK_EQ 的每个参数只检查一次。
  • 输出显示内联代码比较以及值。

【问题讨论】:

  • 无法重现 - 请提供您使用的完整命令行。
  • 你使用的是哪个编译器?
  • 我很惊讶您没有收到来自非优化构建的警告。 Foo(3) 永远不会正确,因为类成员引用不会延长临时对象的寿命。你能用你的宏展示你实际想要完成的事情吗?我们应该能够提供帮助。我会试试看是否有一个欺骗目标。
  • @RyanHaining 非常好。我不知道聚合的行为方式。 TIL :)(顺便说一句,答案+1)
  • 我忘了说,inline 对于在类体中定义成员函数是不必要的,这里的operator bool 隐含为inline

标签: c++


【解决方案1】:

代码具有未定义的行为。调用Foo 的构造函数会导致prvalue 3 的具体化为一个临时对象,该对象绑定到参数x。但该临时对象的生命周期在构造函数退出时结束,在评估 foo.x_ 时将 x_ 作为悬空引用。

您需要提供更多关于您希望 CHECK 宏如何工作的详细信息,然后才能建议一种方法来实现它而无需执行您在此处所做的操作。

【讨论】:

  • 有吗?我没有看到 Foo 导致除了别名之外的任何东西的实现。我累了……
  • 我认为你正在做某事。我添加了一个带有CHECK_EQ 的示例,现在根据优化级别产生不同的输出。如果您能够提出一种方法,以便使用 -O3 标志实现 -O0 行为,我将不胜感激,但您已经解决了最初的问题,所以如果没有更好的问题,我会接受您的回答。
【解决方案2】:

虽然具有用户定义构造函数的类无法延长临时 an aggregate can 的生命周期。通过转换为聚合,我可以使您的方法有效

#include <iostream>

struct CheckEq
{
  int const& x_;
  int const& y_;
  bool const result_;
  explicit operator bool() const { return !result_; }
};

// adding () here for macro safety
#define CHECK_EQ(x, y) if (CheckEq const& check_eq = CheckEq{(x),(y),((x)==(y))}) \
  std::cout << #x << " != " << #y \
    << " (" << check_eq.x_ << " != " << check_eq.y_ << ") "

int main() {
  CHECK_EQ(3,4) << '\n';
}

这对我来说无论有没有 -O3 都会产生相同的输出

【讨论】:

  • 稍作改动,使每个参数只计算一次。再次感谢您的出色回答。
  • 仅供参考 CHECK_EQ(3,std::min(4,5)) 给出警告 -Wall -O3CHECK_EQ(3,std::min(4,5)+0) 没有。大概这是由于std::minint const&amp; 返回到它自己的参数,当传递给CheckEq 时,该参数无法生存。
猜你喜欢
  • 2021-04-15
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2013-12-29
  • 1970-01-01
  • 2018-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多