Gcc -Wshadow слишком строг?

В следующем примере:

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

gcc с -Wshadow выдает предупреждение:

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

Функция len и целое число len имеют разный тип. Почему предупреждение?

Обновить

Я вижу там широкое согласие относительно того, что означает "тень". И с формальной точки зрения, компилятор делает именно то, что хотел.

Однако ИМХО флаг не практичен. Например, часто используемые идиомы setter/getter:

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 каким-то образом бесполезным текстом ссылки. Я не одинок :) Менее строгие проверки могут быть гораздо полезнее.

Ответы

Ответ 1

Это, похоже, решается в новых версиях GCC.

Из версии 4.8 изменения:

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.

И он ссылается на мысли Линуса Торвальдса по этому вопросу: https://lkml.org/lkml/2006/11/28/253

К сожалению, новейший компилятор встроенной системы, в которой я сейчас работаю, по-прежнему основан на gcc 4.6.

Ответ 2

Тот факт, что параметр имеет другой тип от функции-члена, не влияет на то, что параметр затеняет функцию-член.

Почему вы ожидаете, что не будет предупреждения об этом?

Ответ 3

Я не понимаю, почему вы настаиваете только на некоторых конкретных типах затенения. Тень - это затенение, а опасность его одинакова, даже если типы различны и даже если переменная теневая функция, как в вашем случае. Опасность затенения заключается в том, что код может сделать что-то отличное от того, что его автор хотел этого сделать.

Это, BTW, может легко произойти, когда переменная затеняет функцию, поскольку в С++ различие между ними намного тоньше, чем может показаться на первый взгляд.

Например, здесь переменная затеняет функцию

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
  }
};

и я думаю, что довольно очевидно, что из-за затенения код мог бы сделать то, что автор не собирался делать.

Ответ 4

Он делает именно то, что он говорит на коробке. Он предупреждает вас о затенении.

Внутри функции setLen два символа находятся в области с одинаковым именем. len - это имя параметра функции, а также имя функции.

Один затеняет имя другого, поэтому, когда вы пишете код, относящийся к len, вы не можете получить желаемый результат. Так как вы попросили компилятор предупредить вас о том, что для каждого другого есть тени, об этом предупреждает.

Ответ 5

Да, мы можем настроить это предупреждение, чтобы предупредить, только если затенение может быть опасным. Например, не тени для

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

но предупреждайте о локальном переменном shadowning и примере-примере выше.

Чтобы быть более точным, предупреждайте, когда затенение может быть опасным, когда намерение писателя кода может быть нечетким. В случае параметра int и функции-члена с тем же именем ясно, что автор не хочет, чтобы член вызывался, когда он ссылается на параметр.

Я считаю, что это предупреждение о тени является хорошей идеей, очень полезно, просто нужно немного подумать, чтобы не предупредить о совершенно безопасных и ясных случаях. Я, например, могу жить с аргументами, необходимыми для получения префикса или чего-то еще, но я предпочитаю чистые и простые имена.

Ответ 6

Несмотря на то, что это довольно старый вопрос, в GCC> = 7 теперь существует три варианта -Wshadow разному влияют на здравомыслие программистов. С man-страницы 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=compatible-local предупреждение. Поскольку их типы несовместимы, если программист случайно использует один вместо другого, проверка типов обнаружит это и выдаст ошибку или предупреждение. Так что не предупреждение (о затенении) в этом случае не приведет к необнаруженным ошибкам. Использование этого флага вместо -Wshadow=local может уменьшить количество предупреждений, вызванных преднамеренным дублированием.

Это предупреждение включено -Wshadow=local.