Wie hoch ist die Leistung, Sicherheit und Ausrichtung eines Datenmitglieds in einem eingebetteten Char -Array in einer C ++ - Klasse?

StackOverflow https://stackoverflow.com/questions/247639

  •  05-07-2019
  •  | 
  •  

Frage

Ich habe kürzlich eine Codebasis gesehen, von der ich befürchte, dass sie gegen Ausrichtungsbeschränkungen verstoßen. Ich habe es geschrubbt, um ein minimales Beispiel zu erstellen, das unten angegeben ist. Kurz gesagt, die Spieler sind:

  • Schwimmbad. Dies ist eine Klasse, die den Speicher effizient für eine Definition von "effizient" zuordnet. Schwimmbad Es wird garantiert, dass ein Stück Speicher, der für die angeforderte Größe ausgerichtet ist, ausgerichtet ist.

  • OBJ_LIST. Diese Klasse speichert homogene Sammlungen von Objekten. Sobald die Anzahl der Objekte einen bestimmten Schwellenwert überschreitet, ändert sie seine interne Darstellung von einer Liste in einen Baum. Die Größe von OBJ_LIST ist ein Zeiger (8 Bytes auf einer 64-Bit-Plattform). Das besiedelte Geschäft wird dies natürlich überschreiten.

  • Aggregat. Diese Klasse stellt ein sehr häufiges Objekt im System dar. Seine Geschichte geht auf die frühe 32-Bit-Workstation-Ära zurück und war (in derselben 32-Bit-Ära) „optimiert“, um so wenig Platz wie möglich zu nutzen. AggregatS kann leer sein oder eine willkürliche Anzahl von Objekten verwalten.

In diesem Beispiel, Aggregat Gegenstände werden immer von zugewiesen SchwimmbadS, also sind sie immer ausgerichtet. Das einzige Ereignis von OBJ_LIST In diesem Beispiel sind die "versteckten" Mitglieder in Aggregat Objekte, und deshalb werden sie immer mit Verwendung zugewiesen Platzierung neu. Hier sind die Unterstützungskurse:

class Pool
{
public:
   Pool();
   virtual ~Pool();
   void *allocate(size_t size);
   static Pool *default_pool();   // returns a global pool
};

class Obj_list
{
public:
   inline void *operator new(size_t s, void * p) { return p; }

   Obj_list(const Args *args);
   // when constructed, Obj_list will allocate representation_p, which
   // can take up much more space.

   ~Obj_list();

private:
   Obj_list_store *representation_p;
};

Und hier ist aggregiert. Beachten Sie diese Mitgliedserklärung member_list_store_d:

// Aggregate is derived from Lesser, which is twelve bytes in size
class Aggregate : public Lesser
{
public:
   inline void *operator new(size_t s) {
      return Pool::default_pool->allocate(s);
   }

   inline void *operator new(size_t s, Pool *h) {
      return h->allocate(s);
   }

public:

   Aggregate(const Args *args = NULL);
   virtual ~Aggregate() {};

   inline const Obj_list *member_list_store_p() const;

protected:
   char member_list_store_d[sizeof(Obj_list)];
};

Es ist das Datenmitglied, über das ich am meisten besorgt bin. Hier ist der Pseudocode für Initialisierung und Zugriff:

Aggregate::Aggregate(const Args *args)
{
   if (args) {
      new (static_cast<void *>(member_list_store_d)) Obj_list(args);
   }
   else {
      zero_out(member_list_store_d);
   }
}

inline const Obj_list *Aggregate::member_list_store_p() const
{
   return initialized(member_list_store_d) ? (Obj_list *) &member_list_store_d : 0;
}

Möglicherweise sind Sie versucht, vorzuschlagen, dass wir das Char -Array durch einen Zeiger auf die ersetzen OBJ_LIST Geben Sie in Null oder eine Instanz der Klasse initialisiert. Dies gibt die richtige Semantik, verschiebt aber nur die Speicherkosten. Wenn der Speicher noch eine Prämie stand (und dies könnte sein, ist dies eine EDA -Datenbankdarstellung) und das Zeichenarray durch einen Zeiger auf eine ersetzt OBJ_LIST würde einen weiteren Zeiger in dem Fall kosten, wenn Aggregat Objekte tun Mitglieder haben.

Außerdem möchte ich hier nicht wirklich von der Hauptfrage abgelenkt werden, nämlich die Ausrichtung. ich denken Das obige Konstrukt ist problematisch, kann aber nicht mehr im Standard als eine vage Diskussion über das Ausrichtungsverhalten des „Systems/die Bibliothek“ nicht finden Neu.

Tut das obige Konstrukt etwas mehr als gelegentlich einen Rohrstand?

Bearbeiten: Mir ist klar, dass es Möglichkeiten gibt ersetzen Der Ansatz unter Verwendung des eingebetteten Char -Arrays. So auch die ursprünglichen Architekten. Sie verworfen sie, weil das Gedächtnis eine Prämie war. Wenn ich jetzt einen Grund habe, diesen Code zu berühren, werde ich ihn wahrscheinlich ändern.

Meine Frage nach den Ausrichtungsfragen, die diesem Ansatz innewohnt, ist das, was ich hoffe, dass die Menschen angehen werden. Vielen Dank!

War es hilfreich?

Lösung

OK - hatte die Chance, es richtig zu lesen. Sie haben ein Ausrichtungsproblem und rufen ein undefiniertes Verhalten auf, wenn Sie als OBJ_LIST auf das Char -Array zugreifen. Höchstwahrscheinlich wird Ihre Plattform eines von drei Dingen tun: Lassen Sie Sie damit davonkommen, lassen Sie sich damit bei einer Laufzeitstrafe davonkommen oder stürmen gelegentlich mit einem Busfehler ab.

Ihre tragbaren Optionen, um dies zu beheben, sind:

  • Weisen Sie den Speicher mit Malloc oder einer globalen Allokationsfunktion zu, aber Sie denken, dass dies zu teuer ist.
  • Wie Arkadiy sagt, machen Sie Ihren Puffer zu einem OBJ_List -Mitglied:

    Obj_list list;
    

Aber Sie möchten jetzt nicht die Baukosten bezahlen. Sie können dies mildern, indem Sie einen Inline -DO -nichts -Konstruktor bereitstellen, der nur zum Erstellen dieser Instanz verwendet werden kann - wie veröffentlicht der Standardkonstruktor. Wenn Sie dieser Route folgen, sollten Sie sich nachdrücklich auf den DTOR aufrufen

list.~Obj_list();

Bevor Sie eine Platzierung in diesen Speicher machen.

Andernfalls denke ich, dass Sie nicht tragbare Optionen haben: entweder auf die Toleranz Ihrer Plattform gegenüber falsch ausgerichteten Zugriffsern verlassen oder nicht portable Optionen verwenden, die Ihr Compiler Ihnen gibt.

Haftungsausschluss: Es ist durchaus möglich, dass mir ein Trick mit Gewerkschaften oder solchen fehlt. Es ist ein ungewöhnliches Problem.

Andere Tipps

Die Ausrichtung wird vom Compiler gemäß seinen Ausfällen ausgewählt. Dies wird wahrscheinlich als vier Bytes unter GCC / MSVC enden.

Dies sollte nur ein Problem sein, wenn Code (SIMD/DMA) vorhanden ist, für die eine spezifische Ausrichtung erforderlich ist. In diesem Fall sollten Sie in der Lage sein, Compiler-Direktiven zu verwenden, um sicherzustellen, dass member_list_store_d ausgerichtet ist oder die Größe durch (Ausrichtung 1) erhöht und einen entsprechenden Versatz verwenden.

Können Sie einfach eine Instanz von OBJ_List innerhalb des Aggregats haben? Iow, etwas in der Richtung von

Klassenaggregat: public locker {... geschützt: obj_listliste; };

Ich muss etwas vermissen, aber ich kann nicht herausfinden, warum das schlecht ist.

In Bezug auf Ihre Frage ist es perfekt Compiler -abhängig. Die meisten Compiler richten jedoch standardmäßig jedes Mitglied an der Wortgrenze aus, auch wenn der Typ des Mitglieds nicht für den korrekten Zugriff ausgerichtet werden muss.

Wenn Sie eine Ausrichtung Ihrer Strukturen sicherstellen möchten, machen Sie einfach eine

// MSVC
#pragma pack(push,1)

// structure definitions

#pragma pack(pop)

// *nix
struct YourStruct
{
    ....
} __attribute__((packed));

Um sicherzustellen

Zuordnen das Char -Array member_list_store_d Mit malloc oder globalem Betreiber neu [], von denen einer Speicher für jeden Typ ausgerichtet ist.

Bearbeiten: Lesen Sie einfach das OP noch einmal - Sie möchten nicht für einen anderen Zeiger bezahlen. Wird morgens wieder lesen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top