Warum gibt es std::make_unique
in der Standard-C ++ 11-Bibliothek keine Funktionsvorlage? ich finde
std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));
ein bisschen ausführlich. Wäre das Folgende nicht viel schöner?
auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);
Dies verbirgt das new
schön und erwähnt den Typ nur einmal.
Wie auch immer, hier ist mein Versuch einer Implementierung von make_unique
:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Ich habe eine ganze Weile std::forward
gebraucht, um das Zeug zu kompilieren, aber ich bin mir nicht sicher, ob es richtig ist. Ist es? Was genau bedeutet std::forward<Args>(args)...
das? Was macht der Compiler daraus?
c++
c++11
variadic-templates
unique-ptr
perfect-forwarding
Fredoverflow
quelle
quelle
unique_ptr
ein zweiter Vorlagenparameter erforderlich ist, den Sie irgendwie berücksichtigen sollten - das unterscheidet sich vonshared_ptr
.make_unique
mit einem benutzerdefinierten deleter, weil offensichtlich ordnet sie über einfache altennew
und daher muss schlicht verwenden altdelete
:)make_unique
würde sich also auf dienew
Zuweisung beschränken ... Nun, es ist in Ordnung, wenn Sie ihn schreiben möchten, aber ich kann sehen, warum so etwas nicht zum Standard gehört.make_unique
Vorlage, da der Konstruktor vonstd::unique_ptr
explizit ist und es daher ausführlich ist,unique_ptr
von einer Funktion zurückzukehren. Außerdem würde ich lieber verwendenauto p = make_unique<foo>(bar, baz)
alsstd::unique_ptr<foo> p(new foo(bar, baz))
.make_unique
kommt hereinC++14
, siehe isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meetingAntworten:
Herb Sutter, Vorsitzender des C ++ - Standardisierungsausschusses, schreibt in seinem Blog :
Er gibt auch eine Implementierung an, die mit der vom OP angegebenen identisch ist.
Bearbeiten:
std::make_unique
Jetzt ist Teil von C ++ 14 .quelle
make_unique
Funktionsvorlage selbst garantiert keine ausnahmesicheren Aufrufe. Es beruht auf der Konvention, dass der Anrufer sie verwendet. Im Gegensatz dazu basiert die strikte statische Typprüfung (die den Hauptunterschied zwischen C ++ und C darstellt) auf der Idee , die Sicherheit über Typen zu erzwingen . Und dafürmake_unique
kann einfach eine Klasse statt Funktion sein. Siehe zum Beispiel meinen Blog-Artikel vom Mai 2010. Er ist auch mit der Diskussion auf Herbs Blog verknüpft.make_unique
eine Klasse zu erstellen, denke ich jetzt, dass es besser ist, eine Funktion zu erstellenmake_unique_t
, die a erzeugt . Der Grund dafür ist ein Problem mit der perversesten Analyse :-).make_unique
die starke Ausnahmegarantie bietet. Oder Sie mischen das Tool mit seiner Verwendung. In diesem Fall ist keine Funktion ausnahmesicher. Bedenken Sievoid f( int *, int* ){}
, bietet eindeutig dieno throw
Garantie, aber nach Ihrer Argumentation ist es nicht ausnahmsicher, da es missbraucht werden kann. Schlimmer noch,void f( int, int ) {}
ist auch keine Ausnahme sichertypedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))
make_unique
wie oben umgesetzt und du mich von Sutter auf einen Artikel verweisen, der Artikel , dass mein Google-Fu mich , dass in Staaten daraufmake_unique
bietet die starke Ausnahme Garantie , die über Ihre Aussage widerspricht. Wenn Sie einen anderen Artikel haben, bin ich daran interessiert, ihn zu lesen. Meine ursprüngliche Frage lautet also: Wie istmake_unique
(wie oben definiert) keine Ausnahme sicher? (Nebenbemerkung: Ja, ich denke, dasmake_unique
verbessert die Ausnahmesicherheit an Stellen, an denen sie angewendet werden kann.)make_unique
Funktion. Zuerst sehe ich nicht, wie unsicher dieser ist, und ich sehe nicht, wie das Hinzufügen eines zusätzlichen Typs ihn sicherer machen würde . Was ich weiß ist, dass ich daran interessiert bin , die Probleme zu verstehen, die diese Implementierung haben kann - ich kann keine sehen - und wie eine alternative Implementierung sie lösen würde. Was sind die Konventionen , diemake_unique
auf abhängt? Wie würden Sie die Typprüfung verwenden, um die Sicherheit zu gewährleisten? Das sind die beiden Fragen, auf die ich gerne eine Antwort hätte.Schön, aber Stephan T. Lavavej (besser bekannt als STL) hat eine bessere Lösung für
make_unique
, die für die Array-Version korrekt funktioniert.Dies ist auf seinem Core C ++ 6-Video zu sehen .
Eine aktualisierte Version der STL-Version von make_unique ist jetzt als N3656 verfügbar . Diese Version wurde in den Entwurf von C ++ 14 übernommen.
quelle
make_unique
sollte in einem Header stehen. Header sollten keinen Namespace importieren (siehe Punkt 59 in Sutter / Alexandrescus Buch "C ++ Coding Standards"). Durch die Änderungen von Xeo wird vermieden, dass schlechte Praktiken gefördert werden.std::make_shared
ist nicht nur eine Abkürzung fürstd::shared_ptr<Type> ptr(new Type(...));
. Es macht etwas, was man ohne es nicht machen kann.Um seine Arbeit zu erledigen,
std::shared_ptr
muss zusätzlich zum Speichern des Speichers für den eigentlichen Zeiger ein Verfolgungsblock zugewiesen werden. Da jedochstd::make_shared
das tatsächliche Objekt zugewiesen wird, ist es möglich, dassstd::make_shared
sowohl das Objekt als auch der Verfolgungsblock in demselben Speicherblock zugewiesen werden .Während
std::shared_ptr<Type> ptr = new Type(...);
also zwei Speicherzuordnungen (eine für dienew
, eine imstd::shared_ptr
Verfolgungsblock) vorhandenstd::make_shared<Type>(...)
wären , würde ein Speicherblock zugewiesen .Das ist wichtig für viele potentielle Nutzer von
std::shared_ptr
. Das einzige, was einstd::make_unique
tun würde, ist etwas bequemer. Nichts weiter als das.quelle
Nichts hindert Sie daran, Ihren eigenen Helfer zu schreiben, aber ich glaube, dass der Hauptgrund für die Bereitstellung
make_shared<T>
in der Bibliothek darin besteht, dass tatsächlich ein anderer interner Typ eines gemeinsam genutzten Zeigers erstellt wird als dershared_ptr<T>(new T)
, der anders zugewiesen ist, und es gibt keine Möglichkeit, dies ohne den dedizierten zu erreichen Helfer.IhrKorrektur: Dies ist in der Tat nicht der Fall: Ein Funktionsaufruf zum Umschließen desmake_unique
Wrapper hingegen ist nur syntaktischer Zucker um einennew
Ausdruck. Während er für das Auge angenehm aussieht, bringt er nichtsnew
auf den Tisch.new
Ausdrucks bietet Ausnahmesicherheit, beispielsweise in dem Fall, in dem Sie eine Funktion aufrufenvoid f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
. Wenn zweinew
Raws in Bezug aufeinander nicht sequenziert sind, bedeutet dies, dass der andere Ressourcen möglicherweise ausläuft, wenn ein neuer Ausdruck mit einer Ausnahme fehlschlägt. Warum esmake_unique
im Standard kein gibt : Es wurde einfach vergessen. (Dies kommt gelegentlich vor. Es gibt auch kein globales Elementstd::cbegin
im Standard, obwohl es eines geben sollte.)Beachten Sie auch, dass
unique_ptr
ein zweiter Vorlagenparameter erforderlich ist, den Sie irgendwie berücksichtigen sollten. Dies unterscheidet sich vonshared_ptr
der Verwendung der Typlöschung zum Speichern benutzerdefinierter Löscher, ohne sie zum Teil des Typs zu machen.quelle
shared_ptr<T>(new T)
verwendet einen von ihnen,make_shared<T>()
verwendet einen anderen. Das zuzulassen ist eine gute Sache, und die geteilte Version ist in gewisser Weise der leichteste gemeinsame Zeiger, den Sie bekommen können.shared_ptr
einen Block dynamischen Speichers zu, um die Anzahl und die Aktion "Disposer" beim Erstellen von a aufrechtzuerhaltenshared_ptr
. Wenn Sie den Zeiger explizit übergeben, muss ein "neuer" Block erstellt werden. Wenn Sie ihn verwendenmake_shared
, können Sie Ihr Objekt und die Satellitendaten in einem einzigen Speicherblock (einemnew
) bündeln, was zu einer schnelleren Zuweisung / Freigabe, weniger Fragmentierung und (normalerweise) führt ) besseres Cache-Verhalten.In C ++ wird 11
...
(im Vorlagencode) auch für die "Pack-Erweiterung" verwendet.Voraussetzung ist, dass Sie es als Suffix eines Ausdrucks verwenden, der ein nicht erweitertes Paket von Parametern enthält, und dass der Ausdruck einfach auf jedes der Elemente des Pakets angewendet wird.
Bauen Sie zum Beispiel auf Ihrem Beispiel auf:
Letzteres ist falsch, denke ich.
Außerdem kann ein Argumentpaket nicht an eine nicht erweiterte Funktion übergeben werden. Ich bin mir über ein Paket von Vorlagenparametern nicht sicher.
quelle
std::forward<Args>(args)...
, erweitert aufforward<T1>(x1), forward<T2>(x2), ...
.forward
eigentlich erfordert immer einen Template-Parameter, nicht wahr?Inspiriert von der Implementierung von Stephan T. Lavavej fand ich es vielleicht schön, ein make_unique zu haben, das Array-Extents unterstützt. Es ist auf Github und ich würde gerne Kommentare dazu bekommen. Damit können Sie Folgendes tun:
quelle