make_unique e inoltro perfetto

Perché non esiste un modello di funzione std::make_unique nella libreria standard C ++ 11? io trovo

 std::unique_ptr p(new SomeUserDefinedType(1, 2, 3)); 

un po ‘prolisso. Il seguente non sarebbe molto più bello?

 auto p = std::make_unique(1, 2, 3); 

Ciò nasconde il new e menziona il tipo una sola volta.

Ad ogni modo, ecco il mio tentativo di implementare make_unique :

 template std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } 

Mi ci è voluto un po ‘per ottenere la std::forward stuff da compilare, ma non sono sicuro che sia corretta. È? Cosa significa esattamente std::forward(args)... significa? Che ne pensa il compilatore?

Herb Sutter, presidente del comitato di standardizzazione del C ++, scrive sul suo blog :

Che C ++ 11 non includa make_unique è in parte una svista, e sarà quasi certamente aggiunto in futuro.

Dà anche un’implementazione identica a quella data dall’OP.

Modifica: std::make_unique ora fa parte di C ++ 14 .

Bello, ma Stephan T. Lavavej (meglio noto come STL) ha una soluzione migliore per make_unique , che funziona correttamente per la versione dell’array.

 #include  #include  #include  template  std::unique_ptr make_unique_helper(std::false_type, Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } template  std::unique_ptr make_unique_helper(std::true_type, Args&&... args) { static_assert(std::extent::value == 0, "make_unique() is forbidden, please use make_unique()."); typedef typename std::remove_extent::type U; return std::unique_ptr(new U[sizeof...(Args)]{std::forward(args)...}); } template  std::unique_ptr make_unique(Args&&... args) { return make_unique_helper(std::is_array(), std::forward(args)...); } 

Questo può essere visto sul suo video Core C ++ 6 .

Una versione aggiornata della versione STL di make_unique è ora disponibile come N3656 . Questa versione è stata adottata nel progetto C ++ 14.

std::make_shared non è solo una scorciatoia per std::shared_ptr ptr(new Type(...)); . Fa qualcosa che non puoi farne a meno.

Per fare il suo lavoro, std::shared_ptr deve allocare un blocco di rilevamento oltre a contenere lo spazio per il puntatore reale. Tuttavia, poiché std::make_shared alloca l’object reale, è ansible che std::make_shared sia l’object che il blocco di tracciamento nello stesso blocco di memoria.

Così mentre std::shared_ptr ptr = new Type(...); sarebbero due allocazioni di memoria (una per la new , una nel blocco std::shared_ptr tracking), std::make_shared(...) un blocco di memoria.

Questo è importante per molti potenziali utenti di std::shared_ptr . L’unica cosa che farebbe std::make_unique è leggermente più conveniente. Niente di più.

Mentre nulla ti impedisce di scrivere il tuo helper, credo che il motivo principale per fornire make_shared nella libreria sia che in realtà crea un diverso tipo interno di puntatore condiviso rispetto a shared_ptr(new T) , che è diversamente assegnato, e non c’è modo di ottenere ciò senza l’aiuto dedicato.

L’involucro di make_unique altra parte è un semplice zucchero sintattico attorno a una new espressione, quindi mentre potrebbe sembrare piacevole all’occhio, non porta nulla di new al tavolo. Correzione: non è vero: avere una chiamata di funzione per avvolgere la new espressione fornisce un’eccezione di sicurezza, ad esempio nel caso in cui si chiami una funzione void f(std::unique_ptr &&, std::unique_ptr &&) . Avere due new raw non sincronizzati l’uno rispetto all’altro significa che se una nuova espressione fallisce con un’eccezione, l’altra potrebbe perdere risorse. Per quanto riguarda il motivo per cui non c’è make_unique nello standard: è stato appena dimenticato. (Questo capita occasionalmente. Non c’è std::cbegin lo standard std::cbegin nello standard, anche se dovrebbe std::cbegin uno.)

Nota anche che unique_ptr accetta un secondo parametro di template che dovresti in qualche modo permettere; questo è diverso da shared_ptr , che usa la cancellazione dei tipi per archiviare i deleteri personalizzati senza renderli parte del tipo.

In C ++ 11 ... viene usato (nel codice del template) anche per “pack expansion”.

Il requisito è che lo si usi come suffisso di un’espressione contenente un pacchetto non espanso di parametri e si applicherà semplicemente l’espressione a ciascuno degli elementi del pacchetto.

Ad esempio, costruendo sul tuo esempio:

 std::forward(args)... -> std::forward(1), std::forward(2), std::forward(3) std::forward(args...) -> std::forward(1,2,3) 

Quest’ultimo è errato, penso.

Inoltre, il pacchetto di argomenti non può essere passato a una funzione non espansa. Non sono sicuro di un pacchetto di parametri del modello.

Ispirato all’implementazione di Stephan T. Lavavej, ho pensato che sarebbe stato carino avere un make_unique che supportava estensioni di array, è su github e mi piacerebbe ricevere commenti su di esso. Ti permette di fare questo:

 // create unique_ptr to an array of 100 integers auto a = make_unique(); // create a unique_ptr to an array of 100 integers and // set the first three elements to 1,2,3 auto b = make_unique(1,2,3);