54

考虑以下程序:

#include <array>

int main()
{
  std::array<int, 1> x = { 0 }; // warning!
  x = { { 0 } }; // no warning
  return 0;
}

第一次初始化导致 gcc 4.7.2 上的警告...

main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]

...和铿锵3.1

main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
  std::array<int, 1> x = { 0 };

就标准而言,至少在此示例中,双花括号或单花括号之间应该没有区别。

有两种处理警告的方法:

  1. 把它关掉
  2. 修复代码,让编译器开心

你有什么建议?恕我直言,双卷曲的表情看起来有些难看。另一方面,警告可能会在更复杂的示例中检测到真正的问题。你知道警告可以帮助你的例子吗?

4

4 回答 4

52

-Wmissing-braces-Wall出于您所描述的原因,从 4.8 开始,将不再在 GCC(用于 C++ 模式)中启用。对于当前版本的 GCC,无论是禁用还是忽略警告,您所拥有的代码都会按照应有的方式编写。

该警告可能旨在涵盖代码,例如

struct A { int a; int b; };
struct B { A a; int b; };
B b = {
  1,
  2 // initialises b.a.b, not b.b
};

但是,恕我直言,这已经被 处理得很好-Wmissing-field-initializers,它不会警告您的原始代码。

于 2012-12-16T20:59:15.380 回答
8

我在 Xcode 6.1.1(截至 2015 年 3 月 9 日的当前版本)中收到相同的警告。当我在每个子对象周围添加额外的大括号时,我得到一个错误。当我在整个初始化列表周围添加一组额外的大括号时,警告就会消失。根据标准规范 14882:2011 23.3.2.1 [array.overview] 第 2 小节明确规定

array<T, N> a = { initializer-list };

其中 initializer-list 是一个逗号分隔的列表,最多包含 N 个元素,其类型可转换为 T

Xcode 6.1.1 中的代码结果(下)

array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject

array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =

array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer

array<int, 2> key4 = { {1, 2} }; // no warning and no error

当我们查看 14882:2011 8.5 [dcl.init] 第 1 小节时,我们看到“初始化器列表”可以选择包含“初始化器子句”,它本身可以是“支撑初始化器列表”。所以无论哪种方式都应该是正确的。尽管基于规范,我个人认为单大括号不应该为 std::array 初始化器列表输出编译器警告,而双大括号是矫枉过正的。

于 2015-03-09T07:05:39.157 回答
5

Clang 6.0 抑制了关于缺少大括号的警告。svn 日志说:

当聚合初始化具有单个字段的结构时,抑制 -Wmissing-braces 警告,该字段本身就是聚合。在 C++ 中,std::array 类型的这种初始化保证按标准工作,是完全惯用的,并且 Clang 的“建议”替代方案在技术上是无效的。

-Wmissing-braces因此,如果需要支持,我会在 6.0 之前省略大括号并禁用Clang。

于 2018-01-24T02:18:13.447 回答
3

当使用 忽略 Clang 警告时-Wno-missing-braces,我建议启用-Wmissing-field-initializers(或使用-Wextra,其中也包括它)。否则,您会错过一个有用的警告,如本例所示:

#include <cstdio>

struct A
{
  int i;
  int arr[2];
  int j;
};

void print(const A& a)
{
  printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}

int main() {
  A a = {1, 2, 3}; // this is the critical line
  print(a); // output: i=1, arr={2,3}, j=0

  A b = {1, {2}, 3};
  print(b); // output: i=1, arr={2,0}, j=3

  A c = {1, {2,0}, 3};
  print(c); // output: i=1, arr={2,0}, j=3

  return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
      subobject [-Wmissing-braces]
  A a = {1, 2, 3};
            ^~~~
            {   }
1 warning generated.

$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)

$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
      [-Wmissing-field-initializers]
  A a = {1, 2, 3};
                ^
1 warning generated.

$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)

为了比较,这是 GCC 所做的:

$ g++ -Wall -Wextra example.cpp
(no warning)

$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
   A a = {1, 2, 3};
                 ^

总之:

  • 对于 Clang,我建议-Wno-missing-braces -Wmissing-field-initializers在不丢失其他有用警告的情况下使警告静音
  • GCC 在原始示例中没有抱怨std::array<int, 1> x = { 0 };,因此无需禁用任何警告。但是,我建议启用-Wmissing-field-initializers(或使用-Wextra),因为它不是由-Wall.
于 2016-08-29T15:26:40.753 回答