Небольшая опечатка в моем списке инициализаций вызывает неописуемую боль

Итак, я только что закончил с изнурительным многочасовым отладочным сеансом большого серверного приложения. Ошибка сошла до едва заметной опечатки в конструкторе. В принципе, это было что-то вроде:

template <class T>
class request_handler
{
    public:

    request_handler(T& request, Log& error_log) 
      : m_request(m_request), m_error_log(error_log)
     { 
       /*... some code ... */
     }

    ...
};

Посмотрите на ошибку? Ну, я этого не сделал. Проблема заключается в небольшой опечатке в списке инициализаторов: m_request(m_request) присваивает себе неинициализированную ссылку. Очевидно, он должен читать m_request(request).

Теперь переменная-член m_request имеет тип T&. Итак - есть ли причина, по которой компилятор не предупредил меня, что я использовал здесь неинициализированную переменную?

Используя GCC 4.6 с флагом -Wall, если я скажу:

int x;
x = x;

... он выдаст предупреждение: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

Итак, почему компилятор не предупредил меня, когда я назначил m_request себе: по существу присваивая себе неинициализированную ссылку на себя? Это избавило бы меня от досады.

Ответ 1

Раздражающая ошибка для отслеживания. Оказывается, вам даже не нужны шаблоны для молчания на этом. Это сделает трюк:

class C {
        int a, b;
public:
        C(int t, int z) : a(a), b(z) { };
};

Clang предупреждает об этом с помощью -Wuninitialized.

Хорошие новости для gcc-людей: согласно gnu bugzilla, gcc 4.7.0 исправил это.

Обновление

В gcc 4.7.0 добавьте -Wself-init, чтобы получить это предупреждение (подтверждено sbellef):

tst.cc: В конструкторе 'C:: C (int, int): tst.cc:4:9: warning:' C:: a инициализируется с помощью [-Wuninitialized]

Ответ 2

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

template <class T>
request_handler(T& request, Log& error_log) 
 : request(request), error_log(error_log)
{ 
  /*... some code ... */
}

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