In C++, initialize a class member with 'this' pointer during construction
I'd like to create a class that is associated to another class in some sort of parent-child relationship. For this the "child" class needs a reference to it's parent.
For example:
template <typename T>
class TEvent {
private: T* Owner;
public: TEvent(T* parent) : Owner(parent) {}
};
cla开发者_高级运维ss Foo {
private: TEvent<Foo> Froozle; // see below
};
Now the problem is that I can't initialize the Froozle
instance directly, nor using the instanciation list of Foo's constructor, because this
references are not allowed there. Apart from adding another method setParent(T*)
(which I don't like too much because it means that I have to leave the TEvent<>
instance in an invalid state), is there a way to achieve this?
It is OK to use this
in the initialization list, as long as it is not used to access any members that may not have been initialized yet.
From the standard 12.6.2/7 "Initializing bases and members" (emphasis mine):
Names in the expression-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 toX::a
, initializesX::b
with the value of the constructor parameteri
, initializesX::i
with the value of the constructor parameteri
, and initializesX::j
with the value ofX::i
; this takes place each time an object ofclass X
is created. ][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 mem-initializer to refer to the object being initialized. ]
This is supposed to work; in fact,
template<class T>
class Child {
private:
T *parent;
public:
Child(T *parent) : parent(parent) {}
};
class Parent {
private:
Child<Parent> child;
public:
Parent() : child(this) {}
};
compiles fine for me with both g++ 4.4.5 and clang++ 2.8.
What is failing for you?
I don't think it's failing on you, unless you have the warning level set to 4 (or similar, I assume Visual Studio) and have enabled "treat warnings as errors".
Basically, this warning is A Good Thing, since it won't let you accidentally use the this
pointer when what it points at is yet to be constructed.
However, when you know what you are doing wherever this
is passed in the initialization list, the warning and error caused by this will be annoying.
You can get rid of it (again, assuming Visual Studio) by decorating the constructor (unless it's defined in the class declaration - then you must decorate all the class):
// warning C4355: 'this' : used in base member initializer list
#pragma warning (push)
#pragma warning (disable : 4355)
some_class::some_class()
: ...
{
}
#pragma warning (pop)
If you're looking to suppress the warning, just do this:
class Foo
{
public:
Foo() :
Froozle(get_this())
{}
private:
Foo* get_this()
{
return this;
}
TEvent<Foo> Froozle; // see below
};
The indirection is enough to stop it.
精彩评论