gcc -Wshadow太严格了?

时间:2010-06-02 14:05:34

标签: c++ gcc compilation

在以下示例中:

class A
{
  public:
    int len();
    void setLen(int len) { len_ = len; } // warning at this line
  private:
    int len_;
};

gcc with -Wshadow发出警告:

main.cpp:4: warning: declaration of `len' shadows a member of `this'

函数len和整数len是不同类型的。为什么要警告?

更新

我看到“影子”意味着广泛的共识。 从形式上看,编译器完全按照它的意图行事。

然而恕我直言,旗帜不实用。例如常用的setter / getter idiom:

class A {
   void prop(int prop);  // setter
   int prop() const;     // getter

   int prop;
};

如果有一个警告标志在这种情况下不会发出警告会很好,但是如果“int a”隐藏“int a”,它会发出警告。

在我的遗留代码上添加-Wshadow会发出大量警告,同时我会发现由“影子”问题引起的错误。

我不介意它会被称为“-Wmuch_more_practical_and_interesting_shadow”或 “-Wfoooooo”。

那么,其他 gcc警告标志是否符合我的描述?

更新2

我不是唯一一个认为-Wshadow在某种程度上没用link text的人。我不孤独 :) 不太严格的检查可能会更有用。

7 个答案:

答案 0 :(得分:16)

这似乎是在较新版本的GCC上解决的。

From version 4.8 changelog

The option -Wshadow no longer warns if a declaration shadows a function declaration,
unless the former declares a function or pointer to function, because this is a common
and valid case in real-world code.

它引用了Linus Torvalds关于这个主题的想法:https://lkml.org/lkml/2006/11/28/253

不幸的是,我目前正在使用的嵌入式系统的最新编译器仍然基于gcc 4.6。

答案 1 :(得分:15)

参数与成员函数的类型不同,这一事实不会影响参数隐藏成员函数的事实。

为什么你不期望对此有任何警告?

答案 2 :(得分:9)

我不明白为什么你只坚持某些特定类型的阴影。阴影是阴影,即使类型不同,即使变量影响函数,它的危险也是相同的,就像你的情况一样。阴影的危险在于代码可能会做出与其作者想要做的不同的事情。

当变量影响函数时,这很容易发生,因为在C ++中,两者之间的区别比第一眼看上去要薄得多。

例如,这里的变量会影响函数

struct L { 
  void operator ()(); 
};

struct A {
  void len();

  A(L len) {
    len();
    // Intended to call the member function. Instead got a call to the functor
  }
};

并且我认为很明显,由于阴影代码可能会做一些作者不打算做的事情。

答案 3 :(得分:6)

它完全符合它在盒子上的说法。它警告你阴影。

setLen函数内,两个符号在范围内,它们具有相同的名称。 len是函数参数的名称,也是函数的名称。

一个阴影另一个的名称,因此当您编写引用len的代码时,您可能无法获得所需的结果。由于您要求编译器警告您有关彼此的符号 shadowing ,因此这就是它所警告的内容。

答案 4 :(得分:2)

是的,我们可以调整此警告,以便仅在阴影可能存在危险时发出警告。 例如,不要为

添加阴影

void set(int what).. int what()const ..

但警告局部变量shadowning和上面的functor示例。

更确切地说,警告当阴影可能是危险的时,代码编写者的意图可能不清楚。在int参数和具有相同名称的成员函数的情况下,很明显作者不希望在他/她引用参数时调用该成员。

我发现这个影子警告是一个好主意,非常有帮助,只需要更多的思考就不要警告完全安全和清晰的案例。例如,我可以使用带有前缀或其他内容的参数,但我更喜欢干净简单的名称。

答案 5 :(得分:1)

尽管这是一个相当老的问题,但在GCC >= 7中,现在存在-Wshadow的三个变体,它们对程序员的理智有不同的影响。在GCC 9.1.0的手册页中:

  • -Wshadow=global
  

-Wshadow的默认设置。警告任何(全局)阴影。

  • -Wshadow=local
  

当局部变量遮盖另一个局部变量或参数时发出警告。此警告由-Wshadow = global启用。

  • -Wshadow=compatible-local
  

当局部变量遮蔽另一个类型与遮蔽变量兼容的局部变量或参数时发出警告。在C ++中,类型兼容性是指可以将阴影变量的类型转换为阴影变量的类型。创建此标志(除了-Wshadow=local之外,还基于以下想法:当局部变量遮盖另一个不兼容类型的变量时,很可能是有意的,而不是错误或错字,如以下示例所示:

               for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
               {
                 for (int i = 0; i < N; ++i)
                 {
                   ...
                 }
                 ...
               }
     

由于上面示例中的两个变量“ i”具有不兼容的类型,因此仅启用-Wshadow=compatible-local不会发出警告。因为它们的类型不兼容,所以如果程序员不小心使用一个替代了另一个,则类型检查将捕获该错误并发出错误或警告。因此,在这种情况下不警告(关于阴影)不会导致未检测到的错误。使用此标志代替-Wshadow=local可以减少故意阴影触发的警告数量。

     

此警告已由-Wshadow=local启用。

答案 6 :(得分:0)

从问题的更新部分:

class A {
   void prop(int prop);  // setter
   int prop() const;     // getter

   int prop;
};

这只是一个错误;您不能同时具有成员变量和名称相同的方法。

相对于您的示例而言,提供工作界面的最小更改是:

class A {
public:
  void prop(int prop);  // setter
  int prop() const;     // getter

private:
   int prop_;
};