Gemäß einem einfachen, intrusiv referenzierten Objektsystem habe ich eine template<typename T> class Handle
, die mit einer Unterklasse von CountedBase
instanziiert werden soll. Handle<T>
enthält einen Zeiger auf T
, und sein Destruktor ruft DecRef
(definiert in CountedBase
) auf diesem Zeiger auf.Optional sicherheitsgeprüft bei möglicherweise unvollständigem Typ
Normalerweise würde dies zu Problemen führen, wenn sie versuchen, Header-Abhängigkeiten zu begrenzen, indem Vorwärtsdeklarationen mit:
#include "Handle.h"
class Foo; // forward declaration
struct MyStruct {
Handle<Foo> foo; // This is okay, but...
};
void Bar() {
MyStruct ms;
} // ...there's an error here, as the implicit ~MyStruct calls
// Handle<Foo>::~Handle(), which wants Foo to be a complete
// type so it can call Foo::DecRef(). To solve this, I have
// to #include the definition of Foo.
Als Lösung schrieb ich Handle<T>::~Handle()
wie folgt:
template<typename T>
Handle<T>::~Handle() {
reinterpret_cast<CountedBase*>(m_ptr)->DecRef();
}
Bitte beachte, dass ich bin Verwenden Sie reinterpret_cast
hier anstelle von static_cast
, da reinterpret_cast
erfordert die Definition von T
nicht vollständig sein. Natürlich wird es auch keine Zeigeranpassung für mich durchführen ... aber so lange ich mit Layouts vorsichtig bin (T
muss CountedBase
als seinen am weitesten links stehenden Vorfahren haben, darf nicht virtuell von ihm erben, und auf einigen ungewöhnlichen Plattformen , einige zusätzliche Magie ist notwendig), es ist sicher.
Was wäre wirklich schön wäre, wenn ich diese zusätzliche Schicht von static_cast
Sicherheit wo möglich bekommen könnte. In der Praxis ist die Definition T
normalerweise vollständig an dem Punkt, wo Handle::~Handle
instanziiert ist, so dass es ein perfekter Moment, um zu überprüfen, dass T
tatsächlich erbt von CountedBase
. Wenn es unvollständig ist, gibt es nicht viel, was ich tun kann ... aber wenn es vollständig ist, wäre eine Plausibilitätsprüfung gut.
Das bringt uns schließlich zu meiner Frage: Gibt es eine Möglichkeit, eine Kompilierung-Check, dass T
erbt von CountedBase
, die einen (falschen) Fehler führen nicht zu tun, wenn T
unvollständig erscheinen?
[Üblicher Haftungsausschluss: Ich bin mir bewusst, dass es auf diese Weise potentiell unsichere und/oder UB-Aspekte für die Verwendung von unvollständigen Typen gibt. Nach vielen plattformübergreifenden Tests und Profilergebnissen habe ich jedoch festgestellt, dass dies der praktikabelste Ansatz ist, wenn man einige einzigartige Aspekte meines Anwendungsfalls berücksichtigt. Ich habe Interesse an der Kompilierung-Prüfung Frage, nicht ein allgemeiner Code-Review]
Sie möchten also die Kompilierzeitprüfung nur anwenden, wenn 'T' abgeschlossen ist? –
Leider können Sie nicht eine 'is_complete'-Eigenschaft (die nicht UB ist) als diese [one] (http://coliru.stacked-crooked.com/a/56bb09c812f521c6) – Jarod42
@ m.s tun. Ja das ist richtig. – Sneftel