Channel72
Channel72

Reputation: 24719

Small typo in my initializer list causes unspeakable pain

So, I just got through with a grueling multi-hour debug session of a large server application. The error eventually came down to a barely noticeable typo in a constructor. Basically, it was something like:

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 ... */
     }

    ...
};

See the bug? Well, I didn't. The problem is a small typo in the initializer list: m_request(m_request) is assigning an uninitialized reference to itself. Obviously, it's supposed to read m_request(request).

Now, the member variable m_request is of type T&. So - is there some reason the compiler didn't warn me that I was using an uninitialized variable here?

Using GCC 4.6 with the -Wall flag, if I say:

int x;
x = x;

...it will issue a warning: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

So, why didn't the compiler warn me when I assigned m_request to itself: essentially assigning an uninitialized reference to itself? It would have saved me hours of annoyance.

Upvotes: 11

Views: 1443

Answers (2)

Chris Betti
Chris Betti

Reputation: 2923

Annoying bug to track down. It turns out, you don't even need templates to silently fail on this one. This'll do the trick:

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

Clang warns on this with -Wuninitialized.

Good news for gcc folks: according to gnu's bugzilla, gcc 4.7.0 has fixed this.

Update

On gcc 4.7.0, add -Wself-init to get this warning (verified by sbellef):

tst.cc: In constructor ‘C::C(int, int)’: tst.cc:4:9: warning: ‘C::a’ is initialized with itself [-Wuninitialized]

Upvotes: 11

Pubby
Pubby

Reputation: 53037

I like to use the trick of using the same name for the members as the constructor parameters.

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

This will always prevent the error. You have to be careful though as in the function body request refers to argument, not the member. This of course doesn't matter for simple types such as references, but I don't recommend it for classes.

Upvotes: 3

Related Questions