Dans C++, initialisez un membre de classe avec' ceci ' pointeur pendant la construction

je voudrais créer une classe qui est associée à une autre classe, dans une sorte de relation parent-enfant. Pour cela, la classe" enfant " a besoin d'une référence à son parent.

par exemple:

template <typename T>
class TEvent {
    private: T* Owner;
    public: TEvent(T* parent) : Owner(parent) {}
};

class Foo {
    private: TEvent<Foo> Froozle; // see below
};

maintenant le problème est que je ne peux pas initialiser l'instance Froozle directement, ni utiliser la liste d'instanciation du constructeur de Foo, parce que les références this ne sont pas autorisées. En plus d'ajouter une autre méthode setParent(T*) (que je n'aime pas trop car cela signifie que je dois laisser l'instance TEvent<> dans un état invalide), y a-t-il un moyen d'y parvenir?

8
demandé sur sunside 2010-10-24 01:28:49

5 réponses

C'est OK pour utiliser this dans la liste d'initialisation, tant qu'il n'est pas utilisé pour accéder à tout les membres qui n'ont pas été initialisé encore.

13
répondu Björn Pollex 2010-10-23 21:56:59

De la norme 12.6.2/7 "Initialisation de bases et des membres" (l'emphase est mienne):

noms dans l'expression-liste d'un mem-initialiseur sont évalués dans le la portée du constructeur dont la mem-initialiseur est spécifié.

[exemple:

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) {}
};

initialise X::r pour faire référence à X::a , initialise X::b avec la valeur de constructeur paramètre i , initialise X::i avec la valeur de paramètre constructeur i , et initialise X::j avec la valeur de X::i ; ceci a lieu chaque fois qu'un l'objet de class X est créé. ]

[Note: évalués dans le champ d'application de la constructeur, le pointeur this peut être utilisé dans l'expression-liste des un mem-initialiseur pour reportez-vous à la objet en cours d'initialisation. ]

11
répondu Michael Burr 2010-10-23 21:49:45

cela est censé fonctionner; en fait,

template<class T>
class Child {
private:
    T *parent;
public:
    Child(T *parent) : parent(parent) {}
};
class Parent {
private:
    Child<Parent> child;
public:
    Parent() : child(this) {}
};

compile très bien pour moi avec G++ 4.4.5 et clang++ 2.8.

Qu'est-ce qui ne va pas pour vous?

1
répondu ephemient 2010-10-23 21:37:26

si vous cherchez à supprimer l'avertissement, faites juste ceci:

class Foo
{
public:
    Foo() :
    Froozle(get_this())
    {}

private:
    Foo* get_this()
    {
        return this;
    }

    TEvent<Foo> Froozle; // see below
};

l'indirect suffit à l'arrêter.

1
répondu GManNickG 2010-10-23 21:59:58

Je ne pense pas que cela vous fasse défaut, à moins que vous ayez le niveau d'avertissement 4 (ou similaire, je suppose Visual Studio) et que vous ayez activé"traiter les avertissements comme des erreurs".

fondamentalement, cet avertissement est une bonne chose, car il ne vous laissera pas accidentellement utiliser le this pointeur quand ce qu'il pointe est encore à construire.

cependant, quand vous savez ce que vous faites partout où this est passé dans le liste d'initialisation, l'avertissement et erreur causée par la ce sera ennuyeux.

vous pouvez vous en débarrasser (encore une fois, en supposant Visual Studio) en décorant le constructeur (à moins qu'il ne soit défini dans la déclaration de classe - alors vous devez décorer toute la classe):

// warning C4355: 'this' : used in base member initializer list
#pragma warning (push)
#pragma warning (disable : 4355)
some_class::some_class()
: ...
{
}
#pragma warning (pop)
1
répondu Johann Gerell 2010-10-23 22:01:13