Ich habe ein Problem, das durch das Brechen der strikten Aliasing-Regel des Zeigers verursacht wird. Ich habe den Typ T
, der von einer Vorlage kommt, und einen ganzzahligen Typ Int
der gleichen Größe (wie bei sizeof
). Mein Code macht im Wesentlichen folgendes:
Da T
ein beliebiger Wert ist (außer der Größenbeschränkung), der einen Konstruktor haben könnte, kann ich keine Union von T
und Int
erstellen. (Dies ist nur in C ++ 0x erlaubt und wird noch nicht einmal von GCC unterstützt).
Gibt es irgendeine Möglichkeit, den obigen Pseudocode neu zu schreiben, um die Funktionalität zu erhalten und die strengen Aliasing-Regeln zu umgehen? Beachten Sie, dass dies eine Vorlage ist, ich kann T
oder den Wert von some_other_t
nicht kontrollieren; Die Zuordnung und der anschließende Vergleich finden innerhalb des Vorlagencodes statt.
(Zur Erinnerung, der obige Code begann mit GCC 4.5 zu brechen, wenn T
irgendwelche Bitfelder enthält.)
Auf meinem System optimiert GCC sowohl is_T_0()
als auch memcpy()
, was zu einigen wenigen Assemblierungsanweisungen in myfunc()
führt.
Haben Sie von boost::optional
gehört?
Ich muss zugeben, dass mir das wahre Problem hier unklar ist ... aber boost :: optional erlaubt es, nach Wert zu speichern und trotzdem zu wissen, ob der eigentliche Speicher initialisiert wurde oder nicht. Ich lasse auch Konstruktion und Zerstörung an Ort und Stelle zu, also könnte eine gute Passform sein, denke ich.
BEARBEITEN :
Ich glaube, ich habe das Problem endlich verstanden: Sie möchten viele Objekte an verschiedenen Stellen im Speicher zuweisen können, und Sie möchten wissen, ob der Speicher zu diesem Zeitpunkt wirklich ein Objekt enthält oder nicht .
Leider hat Ihre Lösung ein großes Problem: Sie ist falsch. Wenn T
irgendwie durch ein null
Bitmuster dargestellt werden kann, dann wird es sich um einen unitären Speicher handeln.
Sie müssen sich dazu entscheiden, mindestens ein Bit Information hinzuzufügen. Es ist nicht wirklich viel, immerhin sind das nur 3% Wachstum (33 Bits für 4 Bytes).
Sie könnten zum Beispiel einige mimick boost::optional
verwenden, aber in einer Array-Art (um den Padding-Verlust zu vermeiden).
Dann ist es so einfach:
%Vor%Hinweis : Der Einfachheit halber habe ich das Problem der Ausrichtung nicht berücksichtigt. Wenn du nichts über das Thema weißt, lies darüber, bevor du an der Erinnerung herumfummelst:)
Wie wäre es damit:
%Vor%Es ist möglicherweise nicht so effizient, aber es sollte die Warnung loswerden.
ANHANG # 1:
Da T
auf die gleiche Größe wie Int
beschränkt ist, stellen Sie sich einen Dummy-bitweisen Null-Wert vom Typ T
vor und vergleichen Sie direkt mit ihm (anstelle des Vergleichs und des Vergleichs von agaist Int(0)
).
Wenn Ihr Programm single-threaded ist, könnten Sie etwas wie folgt haben:
%Vor% Wenn es sich um ein Multithreading handelt, sollten Sie vermeiden, ein statisches Mitglied zero_
zu verwenden und jede Containerinstanz ihr eigenes zero_
-Member zu besitzen:
ANHANG # 2:
Lassen Sie mich den obigen Zusatz auf eine andere, einfachere Weise stellen:
%Vor% Es fühlt sich an wie ein Hack, aber anscheinend habe ich eine Lösung gefunden: mit volatile
für Int
casting. Im Wesentlichen mache ich jetzt Folgendes:
Das Problem mit bitfield T
ist jetzt weg. Trotzdem bin ich nicht ganz glücklich darüber, da volatile
in C ++ AFAIK nicht gut definiert ist ...
Tags und Links c++ generics reinterpret-cast strict-aliasing type-punning