2009-07-28 9 views
0

Ich habe eine Klassenhierarchie, in der ich weiß, dass eine gegebene Klasse (B) immer in eine zweite (D) abgeleitet wird. Ist es in Bs Konstruktor sicher, den Zeiger this statisch in ein D * zu werfen, wenn ich sicher bin, dass niemand jemals versuchen wird, es zu benutzen, bevor die gesamte Konstruktion fertig ist? In meinem Fall möchte ich eine Referenz auf das Objekt an eine andere Klasse (A) weitergeben.Ist dies während des Baus sicher?

struct A 
{ 
    D & d_; 

    A(D & d) : d_(d) {} 
}; 

struct D; //forward declaration 

struct B 
{ 
    A a; 

    B() : a(std::static_cast<D&>(*this)) {} 
}; 

struct D : public B 
{}; 

Ist dieser Code sicher?

+0

Dies wirft die Frage auf, welche Wertklasse D hinzugefügt wird, wenn B * immer * ein D ist. – JohnMcG

+0

B ist eine Klassenvorlage, die basierend auf ihrem Vorlagenparameter eine Elementfunktion definiert oder nicht. Es gibt mehrere Klassenvorlagen wie diese, die dann von D geerbt werden, um eine von den Vorlagenparametern abhängige Schnittstelle bereitzustellen. –

Antwort

0

@AProgrammer's answer machte mir klar, dass die static_cast könnte leicht vermieden werden, indem die this Zeiger aus der abgeleiteten Klasse an die Basisklasse übergeben. Folglich läuft die Frage auf die Gültigkeit des this Zeigers in der Element-Initialisierer-Liste hinaus.

fand ich die folgende Notiz in dem C++ Standard [12.6.2.7]:

[Hinweis: weil der mem-initializer im Rahmen des Konstruktors ausgewertet werden, die this Zeiger in der Ausdruckliste eines Mem-Initialisierer verwendet werden, um auf das Objekt zu verweisen, das initialisiert wird.

]

Daher this in der Element-Initialisierer-Liste verwendet, ist vollkommen richtig, so denke ich, ist der Code sicher ist (solange keine Mitglieder von D zugegriffen wird).

2

Nein, ist es nicht. Konstruktoren für D-Datenmitglieder sind noch nicht gelaufen.

Da die D-Glieder nicht konstruiert sind, ist D noch nicht vollständig konstruiert, daher sollte technisch ein Verweis auf D ungültig sein. Ich erwarte, dass dies bei den meisten Implementierungen kein Problem ist, aber trotzdem.

Ich würde gerne einen besseren Mechanismus vorschlagen, aber ich denke, "besser" hängt sehr von tatsächlichen Details ab.

+0

Ich weiß, dass D noch nicht konstruiert wurde, deshalb habe ich präzisiert, dass keines seiner Mitglieder aufgerufen wird, bevor die Konstruktion beendet ist. –

+0

In Bezug auf die Gültigkeit des this-Zeigers in der Initialisierungsliste erinnere ich mich auch daran, irgendwo gelesen zu haben, dass es unsicher war, es zu benutzen, aber ist es immer noch wahr, wenn keine Mitglieder angesprochen werden? Ich werde versuchen, den Absatz im Standard zu finden, der diese Frage beantworten kann. –

+0

Anscheinend gibt der Standard explizit an, dass "this" in der Member-Initializer-Liste verwendet werden kann, um auf das zu konstruierende Objekt zu verweisen. –

2

Ich habe nichts darüber gefunden. Ich habe Mühe Gründe zu finden, für die der Code unsicher sein würde, während dies sicher ist:

struct B 
{ 
    A a; 

    B(D& d) : a(d) {} 
}; 

struct D : public B 
{ 
    D() : B(*this) {} 
}; 

aber ich würde wahrscheinlich immer noch die Form ich hier präsentieren verwenden.

+0

Das ist ein netter Weg, um den statischen_cast zu vermeiden, aber das Problem über die Gültigkeit dieses in der Initialisiererliste hält immer noch an. +1 für die sauberere Art, es zu schreiben. –

Verwandte Themen