Angemessene Möglichkeit, virtuelle Funktionen aufgrund der Platzierung neuer Nutzung zu verbieten

8

Was wäre ein guter Ansatz, um bei der Kompilierung / Laufzeit zu überprüfen, dass eine bestimmte Struktur / Klasse keine virtuellen Funktionen hat. Diese Überprüfung ist erforderlich, um bei der Platzierung neu die korrekte Byteausrichtung sicherzustellen.

Wenn Sie so viel wie eine einzelne virtuelle Funktion haben, werden die gesamten Daten um eine vtable -Zeigergröße verschoben, was die Dinge in Verbindung mit dem neuen Operator placement komplett durcheinanderbringt.

Einige weitere Details: Ich brauche etwas, das über alle gängigen Compiler und Plattformen hinweg funktioniert, z. VS2005, VC ++ 10, GCC 4.5 und Sun Studio 12.1 über Windows, Linux und Solaris.

Etwas, das garantiert funktioniert mit dem folgenden Szenario sollte ausreichen:

%Vor%

Sollte sich jemand dafür entscheiden, diese Änderung vorzunehmen:

%Vor%

Es wäre toll, einen Kompilierungsfehler zu sehen, der struct A must not contain virtual functions.

sagt     
Nick 21.06.2011, 06:18
quelle

6 Antworten

1

Sie machen fast sicher etwas falsch.

Da Sie jedoch entschieden haben, etwas falsch zu machen, möchten Sie nicht wissen, ob Ihr TPE keine virtuellen Funktionen hat. Sie möchten wissen, ob es in Ordnung ist, Ihren Typ als Array von Bytes zu behandeln.

In C ++ 03, ist Ihr Typ POD? Wie es der Zufall will, gibt es dafür eine Eigenschaft namens is_pod<T> . Dies wird von Boost / TR1 in C ++ 03 zur Verfügung gestellt, obwohl es einen relativ modernen Compiler benötigt [gcc & gt; 4.3, MSVC & gt; 8, andere weiß ich nicht].

In C ++ 11 können Sie Ihre Anforderungen vereinfachen, indem Sie fragen, ob Ihr Typ trivial kopierbar ist. Auch hier gibt es eine Eigenschaft: is_trivially_copyable<T> .

In jedem Fall gibt es auch is_polymorphic<T> , aber wie gesagt, das ist wirklich nicht das, was Sie wollen. Wenn Sie einen älteren Compiler verwenden, hat dies den Vorteil, dass Sie aus der Box heraus arbeiten, wenn Sie es von Boost erhalten; Es führt den sizeof -Test aus, der an anderer Stelle erwähnt wird, anstatt einfach false für alle benutzerdefinierten Typen zu melden, wie es bei is_pod der Fall ist.

Egal was, Sie sollten besser 120% sicher sein, dass Ihr Konstrukteur ein Noop ist; das ist nicht etwas, das verifiziert werden kann.

Ich habe gerade deine Bearbeitung gesehen. Von dem, was Sie aufgelistet haben, ist Sun Studio das einzige, das nicht die notwendigen Eigenschaften für diese Eigenschaften aufweist. gcc und MSVC haben beide seit mehreren Jahren.

    
Dennis Zickefoose 21.06.2011, 10:31
quelle
7

Es gibt Einrichtungen und Tricks (abhängig von der Version von C ++, die Sie verwenden), um die richtige Ausrichtung für eine Klasse zu erhalten.

In C ++ 0x ist der Befehl alignof ähnlich wie sizeof , gibt aber stattdessen die erforderliche Ausrichtung zurück.

In C ++ 03 ist zunächst zu beachten, dass die Größe ein Vielfaches der Ausrichtung ist, da Elemente in einem Array zusammenhängend sein müssen. Dies bedeutet, dass die Verwendung der Größe als Ausrichtung übereifrig ist (und Platz verschwenden kann), aber gut funktioniert. Mit ein paar Tricks können Sie einen besseren Wert erhalten:

%Vor%

Dieser kleine Helfer gibt eine korrekte Ausrichtung als Kompilierzeitkonstante vor (geeignet für die Template-Programmierung). Es kann größer sein als die minimal erforderliche Ausrichtung (*).

Normalerweise sollte es in Ordnung sein, das Placement neu zu verwenden, es sei denn, Sie verwenden es tatsächlich in einem "rohen Puffer". In diesem Fall sollte die Größe des Puffers mit der folgenden Formel bestimmt werden:

%Vor%

Oder Sie sollten C ++ 0x-Funktionen verwenden:

%Vor%

Ein weiterer Trick, um eine "richtige" Ausrichtung für virtuelle Tabellen zu gewährleisten, ist die Verwendung der Union:

%Vor%

Der Parameter aligner garantiert, dass die buffer für Zeiger und damit auch für Zeiger auf virtuelle Tabellen korrekt ausgerichtet ist.

BEARBEITEN : Zusätzliche Erklärungen wie von @Tony vorgeschlagen.

(*) Wie funktioniert das?

Um es zu verstehen, müssen wir uns in die Gedächtnisrepräsentation einer Klasse vertiefen. Jedes Unterelement einer Klasse hat eine eigene Ausrichtungsanforderung, beispielsweise:

%Vor%

Wobei xxx Padding angibt, so dass c passend ausgerichtet ist.

Was ist die Ausrichtung von A ? Im Allgemeinen ist es die strengere Ausrichtung der Unterelemente, also hier die Ausrichtung von int (was oft 4 ist, da int oft ein 32 bits Integral ist).

Um die Ausrichtung eines beliebigen Typs zu erraten, "tricksen" wir den Compiler mit der AlignHelper Vorlage. Denken Sie daran, dass sizeof(AlignHelper<T>) ein Vielfaches der Ausrichtung sein muss, da Typen zusammenhängend in einem Array angeordnet werden sollten. Daher hoffen wir, dass unser Typ nach dem Attribut c aufgefüllt wird und die Ausrichtung die Größe von c ( 1 nach Definition) plus die Größe der Auffüllung.

%Vor%

Wenn wir sizeof(AlignHelper<T>) - sizeof(T) machen, bekommen wir diesen Unterschied. Überraschenderweise könnte es 0 sein.

Das Problem rührt von der Tatsache her, dass, wenn am Ende von T ein Padding (unbenutzte Bytes) vorhanden ist, ein intelligenter Compiler entscheiden könnte, c dort zu speichern, und somit wäre die Differenz der Größe 0 .

Wir könnten natürlich versuchen, die Größe des c -Attributs rekursiv zu erhöhen (mit einem char-Array), bis wir schließlich eine Differenz ungleich null erhalten. In diesem Fall würden wir eine "enge" Ausrichtung erhalten, aber die einfachste Sache ist zu retten und sizeof(T) zu verwenden, da wir bereits wissen, dass es ein Vielfaches der Ausrichtung ist.

Schließlich gibt es keine Garantie, dass die Ausrichtung, die wir mit dieser Methode erhalten, die Ausrichtung von T ist, wir erhalten ein Vielfaches davon, aber es könnte größer sein, da sizeof implementierungsabhängig ist und ein Compiler entscheiden könnte B. alle Typen auf die Potenz von 2 Grenzen auszurichten.

    
Matthieu M. 21.06.2011 07:06
quelle
3
  

Was wäre ein anständiger Ansatz?   Überprüfen Sie bei der Kompilierung / Laufzeit, dass a   bestimmte Struktur / Klasse hat nicht   irgendwelche virtuellen Funktionen

%Vor%

Über class kann Ihnen helfen, zu überprüfen, ob die gegebene Klasse polymorph ist oder nicht zur Kompilierungszeit . [Hinweis: virtual Vererbung enthält auch eine vtable]

    
iammilind 21.06.2011 07:54
quelle
2

dynamic_cast ist nur für polymorphic classes erlaubt, also können Sie das für eine Kompilierzeitprüfung verwenden.

    
Alok Save 21.06.2011 06:50
quelle
1

Verwenden Sie das Attribut is_pod type von tr1?

    
Tomek 21.06.2011 06:35
quelle
0

Sie können nicht feststellen, ob eine Klasse virtuelle Funktionen nicht hat.

    
Chethan 21.06.2011 06:51
quelle

Tags und Links