Ich überprüfe den C ++ - Code eines anderen für unser Projekt, das MPI für Hochleistungsrechnen verwendet (10 ^ 5 - 10 ^ 6 Kerne). Der Code soll die Kommunikation zwischen (möglicherweise) verschiedenen Maschinen auf verschiedenen Architekturen ermöglichen. Er hat einen Kommentar geschrieben, der etwas in der Art sagt:
Wir würden normalerweise
new
und verwendendelete
, aber hier verwende ichmalloc
undfree
. Dies ist erforderlich, da einige Compiler die Daten beinew
Verwendung unterschiedlich auffüllen , was zu Fehlern bei der Datenübertragung zwischen verschiedenen Plattformen führt. Das passiert nicht mitmalloc
.
Dies passt zu nichts, was ich vom Standard kenne new
vs malloc
Fragen.
Was ist der Unterschied zwischen new / delete und malloc / free?Hinweise auf die Idee, dass der Compiler die Größe eines Objekts anders berechnen könnte (aber warum unterscheidet sich das dann von der Verwendung sizeof
?).
malloc & platzierung neu gegen neu ist eine ziemlich beliebte Frage, spricht aber nur über die new
Verwendung von Konstruktoren, wo malloc
dies nicht der Fall ist, was für diese nicht relevant ist.
Wie versteht malloc die Ausrichtung? sagt, dass das Gedächtnis garantiert richtig ausgerichtet ist mit entweder new
oder malloc
was ich vorher gedacht hatte.
Ich vermute, dass er irgendwann in der Vergangenheit seinen eigenen Fehler falsch diagnostiziert und daraus abgeleitet hat new
und malloc
unterschiedliche Mengen an Polsterung gegeben hat, was meiner Meinung nach wahrscheinlich nicht stimmt. Aber ich kann die Antwort bei Google oder in einer früheren Frage nicht finden.
Hilf mir, StackOverflow, du bist meine einzige Hoffnung!
quelle
malloc
undnew
, wienew
in einigen Umgebungen, einen Block zuweisen, einige Daten am Anfang hinzufügen und einen Zeiger auf eine Position direkt nach diesen Daten zurückgeben. (Ich stimme den anderen innerhalb des Datenblocks zumalloc
undnew
muss dieselbe Art von Polsterung verwenden.)Antworten:
IIRC gibt es einen wählerischen Punkt.
malloc
wird garantiert eine Adresse zurückgeben, die für jeden Standardtyp ausgerichtet ist.::operator new(n)
Es wird nur garantiert, dass eine Adresse zurückgegeben wird, die für einen Standardtyp ausgerichtet ist, der nicht größer als n ist. WennT
es sich nicht um einen Zeichentypnew T[n]
handelt, muss nur eine Adresse zurückgegeben werden, die für ausgerichtet istT
.Dies ist jedoch nur relevant, wenn Sie implementierungsspezifische Tricks spielen, z. B. die unteren paar Bits eines Zeigers zum Speichern von Flags verwenden oder sich auf andere Weise darauf verlassen, dass die Adresse mehr Ausrichtung aufweist, als sie unbedingt benötigt.
Es hat keinen Einfluss auf das Auffüllen innerhalb des Objekts, das notwendigerweise genau das gleiche Layout hat, unabhängig davon, wie Sie den Speicher zugewiesen haben, den es belegt. Es ist daher schwer zu erkennen, wie der Unterschied zu Fehlern bei der Datenübertragung führen kann.
Gibt es Anzeichen dafür, was der Autor dieses Kommentars über Objekte auf dem Stapel oder in Globals denkt, ob sie seiner Meinung nach "wie Malloc gepolstert" oder "wie neu gepolstert" sind? Das könnte Hinweise darauf geben, woher die Idee kam.
Vielleicht ist er verwirrt, aber vielleicht der Code er spricht ist mehr als eine gerade Unterschied zwischen
malloc(sizeof(Foo) * n)
vsnew Foo[n]
. Vielleicht ist es eher wie:vs.
Das heißt, vielleicht sagt er "Ich benutze Malloc", bedeutet aber "Ich packe die Daten manuell an nicht ausgerichteten Orten, anstatt eine Struktur zu verwenden". Eigentlich
malloc
ist es nicht erforderlich, um die Struktur manuell zu packen, aber nicht zu erkennen, dass dies ein geringeres Maß an Verwirrung ist. Es ist erforderlich, das über das Kabel gesendete Datenlayout zu definieren. Verschiedene Implementierungen füllen die Daten unterschiedlich auf, wenn die Struktur verwendet wird.quelle
char
Arrays werden überhaupt nicht aufgefüllt, also bleibe ich bei "verwirrt" als Erklärung.Möglicherweise hat Ihr Kollege an das
new[]/delete[]
magische Cookie gedacht (dies sind die Informationen, die die Implementierung beim Löschen eines Arrays verwendet). Dies wäre jedoch kein Problem gewesen, wenn die Zuordnung, die an der von zurückgegebenen Adresse beginnt,new[]
verwendet worden wäre (im Gegensatz zu der des Zuweisers).Verpackung scheint wahrscheinlicher. Variationen in ABIs können (zum Beispiel) dazu führen, dass am Ende einer Struktur eine andere Anzahl von nachfolgenden Bytes hinzugefügt wird (dies wird durch die Ausrichtung beeinflusst, berücksichtigen Sie auch Arrays). Mit malloc könnte die Position einer Struktur spezifiziert und somit leichter auf ein ausländisches ABI portiert werden. Diese Abweichungen werden normalerweise verhindert, indem die Ausrichtung und Packung der Übertragungsstrukturen festgelegt werden.
quelle
Das Layout eines Objekts kann nicht davon abhängen, ob es mit
malloc
oder zugewiesen wurdenew
. Beide geben dieselbe Art von Zeiger zurück, und wenn Sie diesen Zeiger an andere Funktionen übergeben, wissen sie nicht, wie das Objekt zugewiesen wurde.sizeof *ptr
ist nur abhängig von der Erklärung vonptr
, nicht davon, wie sie vergeben wurde.quelle
Ich glaube, Du hast recht. Das Auffüllen erfolgt durch den Compiler nicht
new
odermalloc
. Padding-Überlegungen gelten auch dann, wenn Sie ein Array oder eine Struktur ohne Verwendungnew
odermalloc
überhaupt deklariert haben . Obwohl ich sehen kann, wie unterschiedliche Implementierungen vonnew
undmalloc
Probleme beim Portieren von Code zwischen Plattformen verursachen können, kann ich nicht erkennen, wie sie Probleme beim Übertragen von Daten zwischen Plattformen verursachen können.quelle
new
als eine nette Verpackung betrachten könnten,malloc
aber aus anderen Antworten geht hervor, dass dies nicht ganz richtig ist. Konsens scheint zu sein, dass die Polsterung bei beiden gleich sein sollte; Ich denke, das Problem mit der Übertragung von Daten zwischen Plattformen tritt nur auf, wenn Ihr Übertragungsmechanismus fehlerhaft ist :)Wenn ich das Layout meiner einfachen alten Datenstruktur mit MS Visual-Compilern steuern möchte, verwende ich diese
#pragma pack(1)
. Ich nehme an, eine solche Precompiler-Direktive wird für die meisten Compiler unterstützt, wie zum Beispiel gcc .Dies hat zur Folge, dass alle Felder der Strukturen ohne Leerzeichen hintereinander ausgerichtet werden.
Wenn die Plattform am anderen Ende dasselbe tut (dh ihre Datenaustauschstruktur mit einem Abstand von 1 kompiliert), passen die auf beiden Seiten abgerufenen Daten gut zusammen. Daher musste ich in C ++ nie mit Malloc spielen.
Im schlimmsten Fall hätte ich in Betracht gezogen, den neuen Operator zu überladen, da er einige knifflige Dinge ausführt, anstatt malloc direkt in C ++ zu verwenden.
quelle
pragma pack
oder ähnliches? Mir ist klar, dass es nicht Teil des Standards sein wird.Dies ist meine wilde Vermutung, woher dieses Ding kommt. Wie Sie bereits erwähnt haben, liegt das Problem bei der Datenübertragung über MPI.
Persönlich implementiere ich für meine komplizierten Datenstrukturen, die ich über MPI senden / empfangen möchte, immer Serialisierungs- / Deserialisierungsmethoden, die das Ganze in / aus einem Array von Zeichen packen / entpacken. Aufgrund des Auffüllens wissen wir nun, dass diese Größe der Struktur größer sein kann als die Größe ihrer Elemente, und daher muss auch die ungepolsterte Größe der Datenstruktur berechnet werden, damit wir wissen, wie viele Bytes gesendet / empfangen werden.
Wenn Sie beispielsweise
std::vector<Foo> A
mit dieser Technik über MPI senden / empfangen möchten , ist es falsch anzunehmen, dass die Größe des resultierenden ZeichenarraysA.size()*sizeof(Foo)
im Allgemeinen ist. Mit anderen Worten, jede Klasse, die Serialisierungs- / Deserialisierungsmethoden implementiert, sollte auch eine Methode implementieren, die die Größe des Arrays angibt (oder das Array noch besser in einem Container speichert). Dies könnte der Grund für einen Fehler sein. Auf die eine oder andere Weise hat dies jedoch nichts mitnew
vs zu tun,malloc
wie in diesem Thread ausgeführt.quelle
In c ++: wird das
new
Schlüsselwort verwendet, um bestimmte Speicherbytes in Bezug auf eine Datenstruktur zuzuweisen. Sie haben beispielsweise eine Klasse oder Struktur definiert und möchten Speicher für das Objekt zuweisen.oder
In allen Fällen benötigen Sie jedoch den definierten Datentyp (Klasse, Struktur, Union, Int, Char usw.), und es werden nur die Speicherbytes zugewiesen, die für das Objekt / die Variable erforderlich sind. (dh Vielfache dieses Datentyps).
Bei der malloc () -Methode können Sie jedoch beliebige Speicherbytes zuweisen, und Sie müssen den Datentyp nicht immer angeben. Hier können Sie es in wenigen Möglichkeiten von malloc () beobachten:
oder
oder
quelle
malloc ist eine Art von Funktion und new ist eine Art von Datentyp in c ++ in c ++, wenn wir malloc verwenden, als wir müssen, und typecast verwenden sollten, sonst gibt Ihnen der Compiler einen Fehler und wenn wir einen neuen Datentyp für die Zuweisung von Speicher verwenden, brauchen wir ihn nicht zu typisieren
quelle