You can get it to work, you can even do so without breaking the implementation out into multiple files; however, from the MSDN:
The this pointer is valid only within nonstatic member functions. It cannot be used in the initializer list for a base class.
Good point! We're not using it in a base class in this example, though.
The base-class constructors and class member constructors are called before this constructor.
That is saying is that the base class constructor and member-variable constructors get called before your class's constructor's code gets executed.
In effect, you've passed a pointer to an unconstructed object to another constructor. If those other constructors access any members or call member functions on this, the result will be undefined.
Yep, that's what I mentioned, poorly worded, in my previous post: "[your class] isn't fully constructed yet, so you have to make sure Thingy's constructor doesn't actually use it yet - but the address is valid"
You should not use the this pointer until all construction has completed.
Indeed. So we're not using it. Just passing it.
It triggers a warning that most developers elevate to an error. My understanding is that the C++ language specification doesn't insist that 'this' be defined until the class's user defined constructor enters scope but it just so happens that the Visual Studio implementation defines it before churning through the initializer list so you can get off with a warning.
As long as it has the memory address of the class, we can safely pass it around, afaik. However, just because it has the memory address doesn't mean the memory has been initialized (it hasn't been, in this case). Since the memory isn't initialized, then we can't safely read or write to the pointer when we dereference it.
I might be mistaken about this! I was trying to look it up in the C++ standard, but I'm not familiar with the standard, so I didn't come up with a clear answer... but it seemed to reinforce what I was saying.
The closest I found was this quote highlighted in red below, and a few examples of valid code snippets in the standard that uses the 'this' pointer: (The code comments are part of the standard's example also)
To form a pointer to (or
access the value of) a direct non-static member of an object obj, the construction of obj shall have started
and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing
the member value) results in undefined behavior. { Example:
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X
{
E() : D(this), // undefined: upcast from E* to A*
// might use path E* ? D* ? A*
// but D is not constructed
// D((C*)this), // defined:
// E* ? C* defined because E() has started
// and C* ? A* defined because
// C fully constructed
X(this) { // defined: upon construction of X,
// C/B/D/A sublattice is fully constructed
}
};
—end example }
§ 12.6.2 paragraph 12 (...I think. I'm still learning how to read this thing)
Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. { Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) { }
};
initializes X::r to refer to X::a, initializes X::b with the value of the constructor parameter i, initializes
X::i with the value of the constructor parameter i, and initializes X::j with the value of X::i; this takes
place each time an object of class X is created. —end example } { Note: Because the mem-initializer are
evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a meminitializer to refer to the object being initialized. —end note }
(This is from N3376, which is a draft version a dozen or so days after the C++11 standard. i.e. it is the C++11 standard with one or two minor corrections)
It's dangerous because you don't know whether the constructor of the class you are passing the 'this' pointer to tries to access it or not. But it's is valid and standard, as far as I can tell. Though I still can't find a guaranteed firm statement in the standard, the examples of valid code and the highlighted note hint at it.
I use it in the MinGW compiler, and I haven't noticed a warning, but I might have it accidentally disabled or something.
The C++FAQ says:
Some people feel you should not use the this pointer in a constructor because the object is not fully formed yet. However you can use this in the constructor (in the {body} and even in the initialization list) if you are careful.
[...snip...]
Here is something that sometimes works: if you pass any of the data members in this object to another data member's initializer, you must make sure that the other data member has already been initialized. The good news is that you can determine whether the other data member has (or has not) been initialized using some straightforward language rules that are independent of the particular compiler you're using. The bad news is that you have to know those language rules (e.g., base class sub-objects are initialized first (look up the order if you have multiple and/or virtual inheritance!), then data members defined in the class are initialized in the order in which they appear in the class declaration). If you don't know these rules, then don't pass any data member from the this object (regardless of whether or not you explicitly use the this keyword) to any other data member's initializer! And if you do know the rules, please be careful.
So again he's saying it's dangerous if you try to access a member-variable that hasn't been constructed yet.
But you can still safely store the 'this' pointer for later use. Leastwise, that's what I get out of it.