11

所以,我刚刚完成了一个大型服务器应用程序的耗时数小时的艰苦调试会话。该错误最终归结为构造函数中几乎不明显的错字。基本上,它是这样的:

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&。那么 - 编译器是否有某种原因没有警告我我在这里使用了未初始化的变量?

使用带有-Wall标志的 GCC 4.6,如果我说:

int x;
x = x;

...它会发出警告:warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

那么,为什么当我分配m_request给自己时编译器没有警告我:本质上是给自己分配一个未初始化的引用?它会为我节省数小时的烦恼。

4

2 回答 2

11

令人讨厌的错误要追踪。事实证明,您甚至不需要模板就可以在此模板上静默失败。这可以解决问题:

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:警告:'C::a'用自身初始化[-Wuninitialized]

于 2012-05-21T01:34:12.660 回答
3

我喜欢使用与构造函数参数相同的成员名称的技巧。

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

这将始终防止错误。您必须小心,因为函数体request中指的是参数,而不是成员。这对于引用等简单类型当然无关紧要,但我不建议将它用于类。

于 2012-05-21T01:42:28.303 回答