hacer un reenvío único y perfecto


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

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

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

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

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

De todos modos, aquí está mi intento de una implementación de 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)...));
}

Me llevó bastante tiempo obtener el std::forward material para compilar, pero no estoy seguro de si es correcto. Es? ¿Qué significa exactamente std::forward<Args>(args)...? ¿Qué hace el compilador de eso?

Author: Xeo, 2011-08-12

6 answers

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

Que C++11 no incluya make_unique es en parte un descuido, y es casi seguro que se añadirá en el futuro.

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

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

 152
Author: user763305,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-22 16:08:31

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

#include <memory>
#include <type_traits>
#include <utility>

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::false_type, Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::true_type, Args&&... args) {
   static_assert(std::extent<T>::value == 0,
       "make_unique<T[N]>() is forbidden, please use make_unique<T[]>().");

   typedef typename std::remove_extent<T>::type U;
   return std::unique_ptr<T>(new U[sizeof...(Args)]{std::forward<Args>(args)...});
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return make_unique_helper<T>(std::is_array<T>(), std::forward<Args>(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 se adoptó en el borrador de C++14.

 75
Author: tominator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-23 11:09:29

std::make_shared no es solo una abreviatura de std::shared_ptr<Type> ptr(new Type(...));. Hace algo que usted no puede 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, debido a que 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.

Así que mientras std::shared_ptr<Type> ptr = new Type(...); serían dos asignaciones de memoria (una para el new, una en el std::shared_ptr tracking block), std::make_shared<Type>(...)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.

 19
Author: Nicol Bolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-12 13:29:40

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

Su envoltura make_unique por otro lado es meramente azúcar sintáctica alrededor de una expresión new, por lo que si bien podría parecer agradable a la vista, no aporta nada new a la expresión tabla. Corrección: esto no es cierto: Tener una llamada a una función para envolver la expresión new proporciona seguridad de excepción, por ejemplo, en el caso de que llame a una función void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Tener dos newcrudos que no están secuenciados entre sí significa que si una nueva expresión falla con una excepción, la otra puede filtrar recursos. En cuanto a por qué no hay make_unique en el estándar: Simplemente se olvidó. (Esto sucede ocasionalmente. Tampoco hay 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 de alguna manera debe tener en cuenta; esto es diferente de shared_ptr, que utiliza borrado de tipo para almacenar eliminadores personalizados sin hacerlos parte del tipo.

 19
Author: Kerrek SB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-12 17:38:56

En C++11 ... también se usa (en el código de plantilla) para la "expansión de paquetes".

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

Por ejemplo, basándose en su ejemplo:

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

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

Creo que este último es incorrecto.

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

 12
Author: Matthieu M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-14 19:58:06

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

// create unique_ptr to an array of 100 integers
auto a = make_unique<int[100]>();

// create a unique_ptr to an array of 100 integers and
// set the first three elements to 1,2,3
auto b = make_unique<int[100]>(1,2,3); 
 5
Author: Nathan Binkert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-04 16:45:17