Vor kurzem bin ich auf einige Arten von Lösch-Implementierungen gestoßen, die eine "handgerollte" vtable verwenden - Adobe ASL any_regular_t
ist ein Beispiel, obwohl ich es auch in Boost ASIO gesehen habe (für die Warteschlange der Komplettierungsroutine).
Im Grunde wird dem Elterntyp ein Zeiger auf einen statischen Typ übergeben, der voll von Funktionszeigern ist, die in dem Kindtyp definiert sind, ähnlich zu dem Folgenden ...
%Vor% Meine Frage ist, was ist der Vorteil dieses Idioms ? Soweit ich das beurteilen kann, ist es nur eine Neuimplementierung dessen, was ein Compiler kostenlos zur Verfügung stellen würde. Wird es nicht noch den Overhead einer zusätzlichen Indirection geben, wenn parent_t::invoke
vtbl::invoke
aufruft.
Ich nehme an, dass es wahrscheinlich etwas damit zu tun hat, dass der Compiler in der Lage ist, den Aufruf von vtbl::invoke
oder ähnlichem zu optimieren, aber ich habe nicht genug Erfahrung mit Assembler, um das auszuarbeiten ich selbst.
Eine Klasse mit einer nützlichen vtable muss grundsätzlich dynamisch zugewiesen werden. Während Sie einen festen Speicherpuffer tun und dort reservieren können, ist es ein Aufwand; Sie haben keine vernünftige Kontrolle über die Größe von Instanzen, wenn Sie virtual
gehen. Mit einem manuellen vtable tun Sie das.
Bei einem Blick auf die betreffende Quelle gibt es eine Menge Behauptungen über die Größe verschiedener Strukturen (weil sie in einem Fall in ein Array aus zwei Doubles passen müssen).
Auch eine "Klasse" mit einem handgerollten vtable kann Standardlayout sein; bestimmte Arten von Casting werden legal, wenn Sie dies tun. Ich sehe nicht, dass dies im Adobe-Code verwendet wird.
In einigen Fällen kann es ganz von der vtable getrennt zugewiesen werden (wie ich es tun, wenn ich Sicht-basierten Typ lösche: Ich erstelle eine benutzerdefinierte vtable für den eingehenden Typ, und speichern Sie eine void*
dafür, dann versenden meine Schnittstelle zu dieser benutzerdefinierten vtable). Ich sehe nicht, dass dies im Adobe-Code verwendet wird. aber ein any_regular_view
, das als Pseudoreferenz für any_regular
fungiert, könnte diese Technik verwenden. Ich verwende es für Dinge wie can_construct<T>
oder sink<T>
, oder function_view<Sig>
oder sogar move_only_function<Sig>
(Besitz wird von unique_ptr
behandelt, Operationen über eine lokale vtable mit 1 Eintrag).
Sie können dynamische Klassen erstellen, wenn Sie eine handgesteuerte vtable haben, in der Sie einen vtable-Eintrag zuweisen und die Zeiger auf das setzen, was Sie auswählen (möglicherweise programmgesteuert). Wenn Sie 10 Methoden haben, von denen jede in einem von 10 Zuständen sein kann, würde das 10 ^ 10 verschiedene Klassen mit normalen VTables erfordern. Mit einer handgerollten vtable müssen Sie nur die Lebensdauer jeder Klasse in einer Tabelle verwalten (damit Instanzen die Klasse nicht überleben).
Als Beispiel könnte ich eine Methode verwenden und ihr eine Methode "run before" oder "run after" hinzufügen, auf einer bestimmten -Instanz einer Klasse (mit sorgfältiger Lebensdauerverwaltung), oder für jede Instanz dieser Klasse.
Es ist auch möglich, dass die resultierenden vtables auf verschiedene Arten einfacher sind als compilergenerierte, da sie nicht so mächtig sind. Vom Compiler generierte VTables verarbeiten beispielsweise virtuelle Vererbung und dynamisches Casting. Der Fall der virtuellen Vererbung hat möglicherweise keinen Overhead, es sei denn, sie wird verwendet, aber das dynamische Casting kann Overhead erfordern.
Sie können auch die Kontrolle über die Initialisierung übernehmen. Bei einer vom Compiler generierten vtable wird der Status der Tabelle definiert (oder nicht definiert), wie es der Standard vorschreibt: mit einer handgenerierten Version können Sie sicherstellen, dass alle Invarianten, die Sie auswählen, gehalten werden.
Das OO-Muster existierte in C vor C ++. C ++ wählte einfach ein paar vernünftige Optionen; Wenn Sie zum Pseudo-C-Stil-Handbuch OO zurückkehren, erhalten Sie Zugriff auf diese alternativen Optionen. Sie können Dinge (mit Kleister) anfertigen, so dass sie wie gewöhnliche C ++ - Typen >> für den gelegentlichen Benutzer aussehen, während sie im Inneren alles andere als sind.
Tags und Links c++ type-erasure vtable