views:

693

answers:

5

I have always been a good boy when writing my classes, prefixing all member variables with m_:

class Test {
    int m_int1;
    int m_int2;
public:
    Test(int int1, int int2) : m_int1(int1), m_int2(int2) {}
};

int main() {
    Test t(10, 20); // Just an example
}

However, recently I forgot to do that and ended up writing:

class Test {
    int int1;
    int int2;
public:
    // Very questionable, but of course I meant to assign ::int1 to this->int1!
    Test(int int1, int int2) : int1(int1), int2(int2) {}
};

Believe it or not, the code compiled with no errors/warnings and the assignments took place correctly! It was only when doing the final check before checking in my code when I realised what I had done.

My question is: why did my code compile? Is something like that allowed in the C++ standard, or is it simply a case of the compiler being clever? In case you were wondering, I was using Visual Studio 2008

Thank you.

+2  A: 

I imagine this works because you were using int1 in the initialiser list, and the only things you can initialise are member variables => it was in fact unambiguous which variable was being initialised.

Whether all C++ compilers would be this forgiving is another matter!

AAT
IIRC g++ also authorise that :-).
p4bl0
It is standard C++.
Michael Aaron Safyan
Thank you for the explanation. Of course only member variables can appear outside the parentheses in the initialisation list. But what is inside the parentheses is not perfectly clear. For example, if we have: Test(int int1) : int1(int1+1), int2(int1) {} now what does int1 on the second parentheses mean? Does it mean ::int1 or does it mean this->int1?
Andy
It's just the same as normal function call scoping: Parameters and local variables shadow the class members.
Mark B
+7  A: 

What you have done is standard C++. Only member variables or base classes may be initliazed in the initialization list, so the variable outside the paranthesis is unambiguous. Within the parenthesis, the typical scoping rules apply, and the members are overshadowed by the parameter names.

Michael Aaron Safyan
+1 This is the only answer that catagorically states this is standard C++ as well as giving an explanation.
Rodion Ingles
+12  A: 

Yes, it's valid. The names in the member initializer list are looked up in the context of the constructor's class so int1 finds the name of member variable.

The initializer expression is looked up in the context of the constructor itself so int1 finds the parameter which masks the member variables.

Charles Bailey
Exactly right, and concisely put. Bravo! +1
Drew Hall
+1, good bravo boy! xD
Johannes Schaub - litb
+2  A: 

This is perfectly normal behavior. As AAT rightly pointed out, there is no ambiguity. The variables initialised by the list have to be class members. This is standard and works across all compliant compilers.

The only thing to remember while using a list like this is that a person who doesn't understand this kind of code may have to maintain it. There is nothing wrong with writing initialisation code like this as long as you know what you are doing.

batbrat
A: 

What you have done is normal. This kind of implementation avoids you from even using the 'this' pointer (in this case).

webgenius