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.
Sie haben einen der wichtigsten Gründe vergessen, warum wir make_unique
bekommen haben. Berücksichtigen Sie den Unterschied zwischen diesen beiden Funktionsaufrufen:
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.