Nützlichkeit von std :: make_unique und std :: make_shared in C ++ 1z

7

Mit C ++ 17 erhalten wir eine Template-Typ-Ableitung für Klassenvorlagen. So könnten viele make Funktionen veraltet sein.

Wie wäre es mit make_unique und make_shared ?

So können wir schreiben

%Vor%

können wir diese Funktionen also vergessen?

    
fen 27.07.2017, 20:26
quelle

2 Antworten

18

Weder unique_ptr noch shared_ptr sind konstruierbar, ohne den Typ explizit anzugeben, da zwischen T* und T[] nicht unterschieden werden kann. Das Schreiben von unique_ptr{new int} ist schlecht formatiert.

Außerdem macht std::make_shared mehr als nur eine std::shared_ptr für Sie, ohne dass Sie new eingeben müssen. Außerdem weist es sowohl das Objekt als auch die Kontrollstruktur in einer einzigen Zuordnung zu, wodurch Sie sowohl eine Zuordnung als auch eine Lokalität für die Änderung der Referenzanzahl erhalten.

    
Barry 27.07.2017, 20:42
quelle
5

Sie haben einen der wichtigsten Gründe vergessen, warum wir make_unique bekommen haben. Berücksichtigen Sie den Unterschied zwischen diesen beiden Funktionsaufrufen:

%Vor%

Eine dieser Funktionen hat einen subtilen Fehler. Kannst du raten, was es ist?

Wenn der Konstruktor vector auslöst, kann etwas sehr Schlimmes passieren. Aufgrund von Bewertungsregeln für C ++ - Funktionsargumentausdrücke ist es möglich, dass die Reihenfolge der Auswertung new T() gefolgt von std::vector<U>{1, 2, 3} gefolgt von unique_ptr<T> des Konstruktors sein kann. Wenn vector auslöst, wird der new ed-Zeiger nie freigegeben.

Das ist schlecht. Und das sind ungefähr 90% der Gründe, warum wir make_unique überhaupt haben.

Nachdem wir das gesagt haben, macht C ++ 17 auch eine Änderung bezüglich der Auswertung von Funktionsargumentausdrücken, die diesen Punkt überflüssig macht. Die Regeln von C ++ 17 garantieren, dass es keine Überlappung zwischen verschiedenen Argumenten gibt, die Argumente initialisieren. Das heißt, der Initialisiererausdruck jedes Arguments wird vollständig abgeschlossen, bevor ein anderer beginnen kann. C ++ 17 garantiert nicht die Reihenfolge der Argumentausdrücke, aber es kann keine Verschachtelung zwischen Unterausdrücken geben.

Im obigen Code kann die Bewertungsreihenfolge zuerst vector oder new T() zuerst lauten. Wenn es jedoch zuerst new T() auswertet, muss es unique_ptr<T>() auswerten, bevor der vector -Konstruktor ausgewertet wird.

In C ++ 17 sind beide sicher. Während also die Argumentableitung der Vorlage nicht make_unique veraltet, funktioniert C ++ 17 als Ganzes.

Natürlich gibt es immer ein Problem mit der Einhaltung von Standards. Ein Compiler implementiert möglicherweise die Konstruktorargumentableitung vor , die die Ordnungsregeln für die Ausdrucksauswertung implementiert. Und es gibt keine Möglichkeit, Ihren Code zu unterbrechen, wenn die Reihenfolge der Ausdrucksauswertung nicht vorhanden ist (sofern Sie sich nicht auf die Feature-Test-Makros verlassen, die einige Compiler nicht unterstützen).

Um sicher zu sein, würde ich vorschlagen, unter diesen Umständen bei make_unique zu bleiben.

Und schließlich gibt es das spezielle Feature von make/allocate_shared : die Möglichkeit, den Kontrollblock und das Objekt im selben Speicher zuzuweisen. Dies ist keine unwichtige Eigenschaft von shared_ptr , und kann nicht mit der Vorlage new repliziert werden.

Also solltest du make_shared wo immer möglich verwenden.

    
Nicol Bolas 28.07.2017 01:24
quelle

Tags und Links