Haben verschiedene neue Operatoren in einem C ++ Programm: Wie? Schlechte Idee? [Duplikat]

9

Ich habe verschiedene Speicherzuweisungen in meinem Code: Eine für CUDA (verwaltet oder nicht), eine für reinen Host-Speicher. Ich könnte mir auch eine Situation vorstellen, in der Sie verschiedene Zuordnungsalgorithmen verwenden möchten - einen für große, lange lebende Blöcke zum Beispiel und einen anderen für kurzlebige, kleine Objekte.

Ich frage mich, wie man ein solches System richtig implementiert.

Platzierung neu?

Meine aktuelle Lösung verwendet Placement new, wobei der Zeiger entscheidet, welcher Speicher und Speicherzuordner verwendet werden soll. Beim Löschen / Aufheben der Zuordnung der Objekte muss dann vorsichtig vorgegangen werden. Derzeit funktioniert es, aber ich denke, es ist keine nette Lösung.

%Vor%

Überladen Sie neue, aber wie?

Ich würde gerne eine Lösung mit einem überladenen new -Operator wählen. Etwas, das wie folgt aussehen wird:

%Vor%

Ich denke, ich könnte dies erreichen, indem ich einen Namespace CudaAllocator und HostAllocator habe, jedes mit einem überladenen new und delete .

Zwei Fragen:

  • Ist es sinnvoll, verschiedene Überladungen von new in einem Code zu haben oder zu haben? dies ein Zeichen für einen Designfehler?
  • Wenn es in Ordnung ist, wie man es am besten implementiert?
Michael 09.07.2015, 11:53
quelle

1 Antwort

3

Es gibt eine Zeit und einen Ort, um den Operator new / delete zu überladen, aber es wird im Allgemeinen nur dann bevorzugt, wenn einfachere Maßnahmen ausgeschöpft wurden.

Der Hauptnachteil von placement new besteht darin, dass der Aufrufer "merkt", wie das Objekt zugewiesen wurde, und die entsprechende Aktion ausführen, um die entsprechende Aufhebung der Zuweisung auszulösen, wenn das Objekt das Ende seiner Lebensdauer erreicht hat. Außerdem muss der Aufrufer das Placement new aufrufen. Dies ist syntaktisch aufwändig (ich nehme an, dass dies die "nicht nette Lösung" ist, die Sie erwähnen.)

Der Hauptnachteil des Überladens von new / delete ist, dass es für einen bestimmten Typ einmal ausgeführt werden soll (wie @JSF gezeigt hat). Dies koppelt ein Objekt eng an die Art und Weise, wie es zugewiesen / freigegeben wird.

Überladen neu / löschen

Vorausgesetzt, diese Einrichtung ist:

%Vor%

Hier ist MyObj mit überladenem new / delete (Ihre Frage):

%Vor%

Druckt Folgendes:

  

MyObj :: neu
MyObj ()
~ MyObj ()
MyObj :: löschen

C Plus Plusy Lösung

Eine bessere Lösung könnte die Verwendung von RAII-Zeigertypen in Kombination mit einer Factory sein, um die Details der Zuweisung und Freigabe des Aufrufers zu verbergen. Diese Lösung verwendet das Placement new , behandelt jedoch die Freigabe, indem eine Deleter-Callback-Methode an eine unique_ptr angehängt wird.

%Vor%

Drucke:

  

allocateCudaMemoryField
  MyObj ()
  allocateHostMemoryField
  MyObj ()
  ~ MyObj ()
  deallocateHostMemoryField
  ~ MyObj ()
  deallocateCudaMemoryField

Generische Version

Das wird besser. Mit derselben Strategie können wir die Zuweisungs- / Freigabe-Semantik für jede Klasse handhaben.

%Vor%

Wird mit einer neuen Klasse S verwendet:

%Vor%

Drucke:

  

allocateCudaMemoryField
      S ()
      allocateHostMemoryField
      S ()
      ~ S ()
      deallocateHostMemoryField
      ~ S ()
      deallocateCudaMemoryField

Ich wollte den Templating-Full-Blast nicht ankurbeln, aber offensichtlich ist dieser Code reif für DRYing out (parametriere die Implementierungen auf der Allokator-Funktion).

Überlegungen

Dies funktioniert sehr gut, wenn Ihre Objekte relativ groß sind und nicht zu oft zugewiesen / freigegeben werden. Ich würde das nicht verwenden, wenn Millionen Objekte in jeder Sekunde kommen und gehen.

Einige der gleichen Strategien funktionieren, aber Sie möchten auch Taktiken wie

betrachten
  • Massenzuordnung / Freigabe zu Beginn / Ende einer Verarbeitungsstufe
  • Objektpools, die eine freie Liste verwalten
  • C ++ - Zuordnungsobjekte für Container wie vector
  • usw.

Es hängt wirklich von Ihren Bedürfnissen ab.

tl; dr

Nein. Überladen Sie nicht new / delete in dieser Situation. Erstellen Sie einen Zuordner, der an Ihre generischen Speicherzuordner delegiert.

    
wesholler 23.07.2015 20:05
quelle

Tags und Links