>>156740>Es geht hier aber nicht um "layout-compatible" sondern um den Fall, dass man ein struct auf seinen ersten Member casten darf (beides Pointer natürlich).
Damit hätte man zwei Zeiger unterschiedlichen Typs auf das gleiche Objekt, und das riecht für Felix nach einem Verstoß gegen die strict-aliasing-Rule.
Felix hat von einem GNOME-Entwickler gefunden (aus dem Jahre 2018):
>There's too much code, when using GObject, that does not follow the strict aliasing rules.
https://bugzilla.gnome.org/show_bug.cgi?id=769183#c3
Und dementsprechend gab es "Use -fno-strict-aliasing for everything".
>>156741>Ich habe nicht gesagt, dass es nie vorkommt, sondern fast nie.
Das "Arrays von Zeigern" im Kot vorkommen, und auch mal ein Zeiger/Referenz darauf rumgereicht wird, kommt Felixens Meinung schon häufiger in OOP-Kot vor. In C++ dann nur eben als
std::vector
. Letzteres sieht man an API-Grenzen weniger, weil C++/STL für Modul-übergreifende Parameterübergabe denkbar ungeeignet ist, weil die kleinste Änderung an der STL die ABI-Stabilität karpott macht, und man daher dazu konvergiert ist, keine C++-API mit STL und STL-Containern anzubieten, insbesondere auf Windows. Die üblichen Alternativen sind eigene Container in der Bibliothek zu implementieren (hallo
QList<T>
) oder Header-only-Bilbiotheken, die direkt mitkompiliert werden.
Wenn man sich normalen C++-OOP-Kot anschaut, kann man das zu Zeiger-Arrays gesagte mal wie folgt transferieren:
Schritt 1: Ein Zeiger-Array und ein
std::vector<Typ *>
ist von der Datenstruktur her hier äquivalent (aber bzgl. der Sprache nicht, siehe unten).
Schritt 2: Ob das nun ein Zeiger oder ein Schlau-Zeiger ist, ist hier äquivalent.
Schritt 3: Einen
std::vector
direkt zu übergeben, oder indirekt als Teil eines
struct
s oder einer
class
zu übergeben, ist hier äquivalent.
Schritt 4: Methoden kriegen einen
this
-Zeiger übergeben.
Ergebnis: Wenn man Kot hat wie
class MyClass
{
std::vector<std::unique_ptr<Base>> v;
public:
void DoSomething()
{
for(auto & i : v)
i->DoSomething();
}
};
dann kriegt
DoSomething
ein Zeiger-Array übergeben. Ist auch wenig überraschend, schließlich kann diese Methode über das Zeiger-Array iterieren.
Das ganze kann man auch umgekehrt machen:
class MyClass
{
Base * b;
public:
void DoSomething()
{
b->DoSomething();
}
};
void f(std::vector<MyClass> & v)
{
for(auto & i : v)
i.DoSomething();
}
Es gibt dann in beiden Fällen Zeiger-Arrays, die ggf. über Umwege an Funktionen übergeben werden. Felix hält obige Kot-Abschnitte für durchaus öfters in C++-OOP-Kot anzutreffend.
Und damit kommt nun Felix zum entscheidenden Unterschied, warum ein Zeiger-Array und
std::vector<Typ *>
eben nur von der Datenstruktur her äquivalent sind (zumindest in Bezug auf den Array-Teil), aber in einem ganz entscheidenden Punkt in der Sprache nicht: In C++ sind
std::vector<Base *>
und
std::vector<Derived *>
vollkommen unabhängige Typen, die nichts miteinander zu tun haben. Man kann vom einen
vector
-Typ nicht zum anderen
vector
-Typ konvertieren, weder implizit noch durch simplen Cast.