0

Простой способ найти неинициализированные переменные-члены

30

Я ищу простой способ обнаружить неинициализированные переменные-члены класса.

Нахождение таких переменных как во время выполнения, так и на этапе компиляции подходит.

На данный момент я ставлю точку останова в конструкторе класса и проверяю переменные по одной.

5 ответ(ов)

0

Если вы используете GCC, вы можете применить флаг -Weffc++, который генерирует предупреждения, когда переменная не инициализирована в списке инициализации членов. Например:

class Foo
{
  int v;
  Foo() {}
};

Приведет к следующему предупреждению при компиляции:

$ g++ -c -Weffc++ foo.cpp -o foo.o
foo.cpp: In constructor ‘Foo::Foo()’:
foo.cpp:4: warning: ‘Foo::v’ should be initialized in the member initialization list

Однако есть и недостатки: флаг -Weffc++ также будет предупреждать вас, если переменная имеет корректный конструктор по умолчанию и инициализация не обязательна. Он также выдает предупреждения, когда вы инициализируете переменную в конструкторе, но не в списке инициализации членов. Дополнительно он дает предупреждения по ряду других стилей C++, таких как отсутствие конструкторов копирования, так что вам, возможно, придется немного почистить свой код, если вы хотите регулярно использовать -Weffc++.

Существует также ошибка, которая вызывает постоянное предупреждение при использовании анонимных объединений, и единственный способ обойти это — отключить предупреждение с помощью:

#pragma GCC diagnostic ignored "-Weffc++"

Несмотря на это, я нашел -Weffc++ невероятно полезным для выявления множества распространенных ошибок в C++.

0

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

В приведенном вами примере кода:

struct Q { 
  int x, y;
  Q() : x(2) {}
  int get_xy() const { return x * y; }
};

Компилятор g++ не выдаст предупреждение о неинициализированной переменной y, если вы вызовете метод get_xy(), поскольку y не инициализирован, и вы собираетесь использовать его в выражении return x * y;. Предупреждение появится только в том случае, если вы вызовете метод get_xy() без присвоения значения переменной y.

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

0

Если вы используете Visual Studio, вы можете скомпилировать программу в режиме отладки, остановить ее в отладчике и проверить, какие переменные инициализированы байтами, содержащими 0xCC (стек) или 0xCD (куча).

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

0

В Visual Studio (MSVC) есть опция компилятора /sdl (включить дополнительные проверки безопасности) (http://msdn.microsoft.com/en-us/library/jj161081.aspx). Эта опция в режиме выполнения:

  • Выполняет инициализацию членов класса. Автоматически инициализирует члены класса типа указателя в ноль при создании объекта (до выполнения конструктора). Это помогает предотвратить использование неинициализированных данных, связанных с членами класса, которые конструктор не инициализирует явно.

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

0

Будьте осторожны! Компиляторские опции, предложенные здесь, не являются ни надежными, ни независимыми от версии. Рассмотрим простой пример:

class A {
  int a;
public:
  void mA() {
    printf("haha");
    ++a;
    int g = 2/a;
    printf("%i\n",g);
  }
};

int main() {
  A a;
  a.mA();
}

При компиляции с g++ -O3 -Weffc++ -Wuninitialized данное код вызывает предупреждение о "неинициализированной" переменной на версиях gcc до 4.6 включительно, тогда как на 4.7 и 4.8 (тестировалось на MacPorts) он проходит без проблем. Интересно, что если мы уберем printf("haha");, то версии 4.7 и 4.8 вновь начинают видеть "неинициализированную" переменную A::a. Clang немного лучше в этом плане, так как он как-то присваивает мусор (вместо удобного 0) неинициализированным переменным, что позволяет быстрее и проще заметить их катастрофические последствия.

Также мне не удалось обнаружить вышеупомянутую неинициализированную переменную A::a с помощью valgrind; может, уважаемые коллеги, предлагающие valgrind, могут предоставить подходящие опции для обнаружения этой ошибки.

В итоге: отличный вопрос, но в данный момент надежных решений не так уж много... (как я это вижу).

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь