make_unique y reenvío perfecto

¿Por qué no hay std::make_unique plantilla de función std::make_unique en la biblioteca estándar de C ++ 11? Encuentro

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

un poco detallado. ¿No sería lo siguiente mucho mejor?

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

Esto oculta lo new muy bien y solo menciona el tipo una vez.

De todos modos, aquí está mi bash de una implementación de make_unique :

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

Me llevó bastante tiempo comstackr todo el material estándar, pero no estoy seguro de si es correcto. ¿Lo es? ¿Qué significa std::forward(args)... exactamente? ¿Qué hace el comstackdor de eso?

Herb Sutter, presidente del comité de normalización de C ++, escribe en su blog :

Que C ++ 11 no incluya make_unique es en parte un descuido, y seguramente se agregará en el futuro.

Él también da una implementación que es idéntica a la dada por el OP.

Edit: std::make_unique ahora es parte de C ++ 14 .

Bien, pero Stephan T. Lavavej (mejor conocido como STL) tiene una mejor solución para make_unique , que funciona correctamente para la versión de matriz.

 #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)...); } 

Esto se puede ver en su video Core C ++ 6 .

Una versión actualizada de la versión de STL de make_unique ahora está disponible como N3656 . Esta versión fue adoptada en el borrador C ++ 14.

std::make_shared no es solo una abreviatura de std::shared_ptr ptr(new Type(...)); . Hace algo que no puedes hacer sin él.

Para hacer su trabajo, std::shared_ptr debe asignar un bloque de seguimiento además de mantener el almacenamiento para el puntero real. Sin embargo, como std::make_shared asigna el objeto real, es posible que std::make_shared asigne tanto el objeto como el bloque de seguimiento en el mismo bloque de memoria.

Entonces, mientras std::shared_ptr ptr = new Type(...); Sería dos asignaciones de memoria (una para el new , uno en el bloque de seguimiento std::shared_ptr ), std::make_shared(...) asignaría un bloque de memoria.

Eso es importante para muchos usuarios potenciales de std::shared_ptr . Lo único que haría un std::make_unique es ser un poco más conveniente. Nada más que eso.

Si bien nada le impide escribir su propia ayuda, creo que la razón principal para proporcionar make_shared en la biblioteca es que en realidad crea un tipo interno diferente de puntero compartido que shared_ptr(new T) , que es diferente asignado, y no hay manera de lograr esto sin el ayudante dedicado.

make_unique otro lado, su envoltorio make_unique es un simple azúcar sintáctico alrededor de una new expresión, por lo que si bien puede parecer agradable a la vista, no aporta nada new a la mesa. Corrección: esto no es cierto: tener una llamada a función para ajustar la new expresión proporciona seguridad de excepción, por ejemplo, en el caso en que se llama a una función void f(std::unique_ptr &&, std::unique_ptr &&) . Tener dos new primas sin secuenciar entre sí significa que si una nueva expresión falla con una excepción, la otra puede perder recursos. En cuanto a por qué no hay make_unique en el estándar: simplemente fue olvidado. (Esto sucede de vez en cuando. Tampoco existe un std::cbegin global en el estándar, aunque debería haber uno).

También tenga en cuenta que unique_ptr toma un segundo parámetro de plantilla que debe permitir de alguna manera; esto es diferente de shared_ptr , que usa borrado de tipo para almacenar modificadores personalizados sin hacerlos parte del tipo.

En C ++ 11 ... se usa (en el código de plantilla) para “expansión de paquete” también.

El requisito es que lo use como un sufijo de una expresión que contenga un paquete de parámetros no expandido, y simplemente aplicará la expresión a cada uno de los elementos del paquete.

Por ejemplo, construyendo sobre tu ejemplo:

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

El último es incorrecto, creo.

Además, el paquete de argumentos no se puede pasar a una función no expandida. No estoy seguro acerca de un paquete de parámetros de plantilla.

Inspirado por la implementación de Stephan T. Lavavej, pensé que sería bueno tener un make_unique que admitiera extensiones de matriz, está en github y me encantaría recibir comentarios al respecto. Te permite hacer esto:

 // 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);