Wie könnte ich den Platzierungsoperator new sinnvoll überladen?

Lesezeit: 7 Minuten

C++ erlaubt Überladen operator new – sowohl global als auch pro Klasse – üblich operator new, operator new[] benutzt mit new[] Aussage und Platzierung operator new separat.

Die ersten beiden dieser drei sind normalerweise für die Verwendung benutzerdefinierter Allokatoren und das Hinzufügen von Tracing überladen. Aber Platzierung operator new scheint ziemlich einfach zu sein – es tut tatsächlich nichts im Inneren. In Visual C++ gibt die Standardimplementierung beispielsweise nur die an den Aufruf übergebene Adresse zurück:

//from new.h
inline void* operator new( size_t, void* where )
{
   return where;
}

Was könnte es sonst tun? Warum und wie könnte ich die Platzierung sinnvoll überlasten operator new?

  • Fragen Sie nach Verwendungen des Überladens des neuen Operators? Das ist eine ziemlich breite Frage.

    – Alexander Rafferty

    9. September ’10 um 8:50

  • @Alexander Rafferty Ich frage speziell nach der Verwendung von Überlastungsplatzierungen neu. Ich kann in diesem speziellen Fall keinen Zweck erkennen.

    – scharfer Zahn

    9. September ’10 um 8:52

  • +1 für den Einstieg in die Header-Dateien.

    – Chubsdad

    9. September ’10 um 9:25

  • +1, interessante Frage, deshalb mag ich SO 🙂

    – Matteo Italien

    9. September ’10 um 9:35

  • Pedantisch: Du nicht Überlast Betreiber neu, du ersetzen es (oder überschreibe es). Überladen bedeutet das Erstellen einer neuen Methode/Funktion mit demselben Namen wie eine vorhandene, aber mit einer anderen Signatur. Beim Ersetzen einer Funktion verwenden Sie die identische Signatur.

    – Adrian McCarthy

    6. Apr. ’11 um 20:35

Die richtige Antwort ist Sie können die Vermittlungsplatzierung nicht neu ersetzen.

§18.4.​1.3 Vermittlungsformulare
Diese Funktionen sind reserviert, ein C++-Programm darf keine Funktionen definieren, die die Versionen in der Standard-C++-Bibliothek ersetzen.

Die Begründung: Der einzige Zweck der Zuweisungs- und Aufhebungsoperatoren besteht darin, Speicher zuzuweisen und freizugeben, so dass bei gegebenem Speicher nichts mehr getan werden sollte. (Der Standard weist ausdrücklich darauf hin, dass diese Funktionen “absichtlich keine andere Aktion ausführen”.)

  • Beeindruckend. Visual C++ 9 lässt das gerne zu.

    – scharfer Zahn

    9. September ’10 um 14:02

  • @sharptooth: Was ist dein Testprogramm? Es überrascht nicht, dass es genauso illegal ist, wie es illegal ist, Dinge (im Allgemeinen) zum hinzuzufügen std Namensraum. Die Sprache selbst ist nicht klüger, aber die Standardbibliothek verbietet es.

    – GManNickG

    9. September ’10 um 14:36

  • Ich habe void* Operator neu ersetzt[](size_t, void* where) indem ich in die Header-Dateien meines Compilers gehe. Es hat gut funktioniert. Eigentlich habe ich es nicht ersetzt — ich habe es entfernt, um es unbrauchbar zu machen, weil es ist unbrauchbar.

    – Paul Du Bois

    22. August ’12 um 4:49

  • @PaulDuBois: Hä? Schlechte Idee, Compilerdateien zu bearbeiten, jetzt können Sie nur auf einer ganz speziellen Konfiguration aufbauen; für welchen Gewinn?

    – GManNickG

    22. August ’12 um 4:55


  • Nicht sinnvoll, Sie können weiterhin klassenspezifische neue Platzierungsvorgänge überschreiben.

    – 0xbaadf00d

    24. Januar ’18 um 8:24

Technisch gesehen eine Platzierung operator new ist irgendwas operator new das erfordert neben der benötigten Speichergröße noch weitere Argumente.

So, new(std::nothrow) X verwendet ein Placement operator new und das tut es auch new(__FILE__, __LINE__) X.

Der einzige Grund für das Überschreiben der operator new(size_t, void*) könnte sein, Tracing-Informationen hinzuzufügen, aber ich denke, der Bedarf dafür wird ziemlich gering sein.

  • Ein Grund für die Implementierung könnte darin bestehen, die Verwendung eines bestimmten Speicherzuordners zu erzwingen; Dies ist bei uns aufgetreten, wenn wir komplexe Dinge unter Windows tun, bei denen es erforderlich war, die Verwendung des Allocators zu erzwingen, der von einer bestimmten DLL anstelle einer anderen verwendet wird. (Ja, verschiedene Bibliotheken verwendeten verschiedene Allocators. Es funktionierte alles, solange der Code übereinstimmte new aus einer lib mit delete aus derselben Lib.)

    – Donal Fellows

    9. September ’10 um 9:16

  • Der erste Satz ist falsch, Platzierung neu hat eine bestimmte Bedeutung. Und die Platzierung neu kann nicht überladen oder ersetzt werden.

    – GManNickG

    09.09.10 um 13:40

  • @GMan: Du hast recht. Es scheint keinen bestimmten Namen für zu geben operator new Überladungen, die zusätzliche Parameter benötigen, obwohl sie normalerweise mit der Platzierungssyntax aufgerufen werden.

    – Bart van Ingen Schenau

    10. September ’10 um 8:19

  • @GMan: new mit zusätzlichen Argumenten aufgerufen wird, heißt “Platzierung neu”, unabhängig davon, ob diese zusätzlichen Daten eine Adresse sind, an der das Objekt konstruiert werden soll. Aus dem Standard “The Neuplatzierung Syntax wird verwendet, um einer Zuordnungsfunktion zusätzliche Argumente zu liefern.” (Abschnitt [expr.new]). Die ersten beiden Sätze der Antwort sind richtig. Das letzte ist jedoch falsch und ersetzt ::operator new(size_t, void*) ist verboten, daher können Sie keine Ablaufverfolgung hinzufügen.

    – Ben Voigt

    31. Dezember ’11 um 3:06

Wie konnte ich den Platzierungsoperator new sinnvoll uberladen
direkt

Ein Beispiel ist in den FAQ von Stroustrup.

  • Ehrlich gesagt verstehe ich dieses Beispiel nicht.

    – scharfer Zahn

    9. September ’10 um 8:58

  • @sharptooth Habe ein ähnliches Beispiel mit einigen zusätzlichen Erklärungen gefunden Hier (obwohl es leichte Ungenauigkeiten gab)

    – blgt

    19. August ’14 um 8:44

Die offensichtlichste Überschreibung wäre, diese Implementierung zu kopieren.

Eine andere sinnvolle Möglichkeit wäre, einige Prüfungen hinzuzufügen (zB um zu überprüfen, ob es innerhalb der Anforderungszone keinen “Bound-Marker” gibt).

Ich denke jedoch, dass der Punkt mehr ist, als Sie es überschreiben MÜSSEN, sobald Sie die anderen überschreiben (für eine bestimmte Klasse), wegen der Mechanismen des Namensnachschlagens (oder es nicht überschreiben, um seine Verwendung zu verhindern, das ist auch in Ordnung) , aber es ist eine bewusste Entscheidung).

Eine schöne Verwendung ist es, eine eigene Speicherverwaltung für einen vorreservierten Bereich zu definieren.

Verschiedene Ansichten über dieselben physischen Daten zu haben (keine Notwendigkeit, die Daten zu verschieben) ist ein anderer intersetierender Zweck. Es ermöglicht Ihnen auch, eine strukturierte Datei als Zeichen in einem Puffer zu lesen und dann ihre logische Struktur zu überlagern, indem Sie ein Objekt dieser Klasse über dem Puffer definieren. Die Kombination dieser Sache mit der Speicherzuordnung von Dateien kann zu großen Leistungsverbesserungen führen. Die speicherabgebildete Hardware… Also, tausend Anwendungen!

  • Könnten Sie bitte ein Beispiel geben? Bei dieser Frage geht es nicht darum, Platzierungen neu aus dem Benutzercode zu verwenden, sondern um das Überladen des Operators.

    – scharfer Zahn

    4. März ’15 um 7:32

Wie konnte ich den Platzierungsoperator new sinnvoll uberladen
Cubbi

Ich habe ein Beispiel gesehen, in dem zwei Argumente neu sind [] wurde überschrieben, um Speicherblöcke zurückzugeben, die mit dem als zusätzliches Argument übergebenen char vorausgefüllt wurden. Ich erinnere mich nicht, was der ursprüngliche Code verwendet hat (wahrscheinlich memset()), aber funktional war es ungefähr so:

#include <iostream>
#include <algorithm>
#include <new>
void* operator new [](size_t n, char c)
{
        char* p = new char[n];
        std::fill(p, p+n, c);
        return p;
}
int main()
{
        char* p = new('a') char[10];
        std::cout << p[0] << p[1] << ".." << p[9] << 'n';
}

obwohl ich denke, dass dies nicht “Placement” neu heißen würde, weil es nicht funktioniert Platzierung. Es könnte wahrscheinlich nützlich sein, wenn es mit Vorlagen versehen wäre, damit es Arrays jeden Typs erstellen kann, die mit einer Kopie des Objekts gefüllt sind, das als zweites Argument übergeben wird … aber dann haben wir sowieso Container dafür.

  • Könnten Sie bitte ein Beispiel geben? Bei dieser Frage geht es nicht darum, Platzierungen neu aus dem Benutzercode zu verwenden, sondern um das Überladen des Operators.

    – scharfer Zahn

    4. März ’15 um 7:32

1641733569 144 Wie konnte ich den Platzierungsoperator new sinnvoll uberladen
Carl Cook

Ich bin mir der Frage nicht ganz sicher, aber Folgendes überschreibt die Platzierung neu auf Klassenebene:

struct Bar {
void* operator new(size_t /* ignored */, void* where) throw() { return where; }
};

int main() {
  char mem[1];
  Bar* bar = new(mem) Bar;
}

Ich glaube, dies ist legales C++ (und kompiliert und läuft gut mit gcc 4.4.6).

Es steht Ihnen frei, die Implementierung dieses Operators nach Belieben zu ändern (einschließlich des Entfernens der throw() -Klausel, was bedeutet, dass der Compiler die where Zeiger auf null, bevor der Konstruktor aufgerufen wird). Gehen Sie jedoch vorsichtig vor.

§18.4.​1.3 ist interessant. Ich glaube, dies gilt nur für die neue Funktion des globalen Operators, nicht für klassenspezifische.

  • Die Frage war, ob eine andere Implementierung möglich war. Was könnte ich sonst tun außer return where;?

    – scharfer Zahn

    23. September ’13 bei 6:56

  • Ah ich sehe. Nun, Sie könnten etwas überprüfen, um sicherzustellen, dass diese Adresse nicht bereits verwendet wird, sich nicht mit bereits zugewiesenem Speicher überschneidet, oder Sie können sogar anpassen where besser ausgerichtet sein (zurückkehren) where + n Byte). So etwas habe ich in der Praxis noch nie erlebt.

    – Carl Cook

    23. September ’13 um 9:35

  • Es wird kompiliert, aber sind Sie sicher, dass Ihre Überschreibung aufgerufen wird?

    – John Lindal

    7. Juni ’18 um 18:51


  • Ja, ich bin mir sicher (da ich dies zuvor im Produktionscode verwenden musste). Um dies zu überprüfen, fügen Sie einen Throw in den Funktionsrumpf ein und erstellen dann eine neue Instanz dieses Typs.

    – Carl Cook

    8. Juni ’18 um 2:52

.

212220cookie-checkWie könnte ich den Platzierungsoperator new sinnvoll überladen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy