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. Предупреждает о любой (глобальной) слежке.
Предупреждать, когда локальная переменная скрывает другую локальную переменную или параметр. Это предупреждение включено -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
.