¿Por qué no hay std::make_unique
una plantilla de función en la biblioteca estándar de C ++ 11? Encuentro
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 new
muy bien y solo menciona el tipo una vez.
De todos modos, aquí está mi intento de implementar 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 std::forward
compilar las cosas, pero no estoy seguro de si es correcto. ¿Lo es? ¿Qué std::forward<Args>(args)...
significa exactamente ? ¿Qué hace el compilador de eso?
c++
c++11
variadic-templates
unique-ptr
perfect-forwarding
flujo libre
fuente
fuente
unique_ptr
toma un segundo parámetro de plantilla que de alguna manera debería permitir, que es diferenteshared_ptr
.make_unique
con un Deleter costumbre, porque obviamente se asigna a través de llanura de edadnew
y por lo tanto debe utilizar el viejo y simpledelete
:)make_unique
se limitaría a lanew
asignación ... bueno, está bien si quieres escribirla, pero puedo ver por qué algo así no es parte del estándar.make_unique
plantilla ya que el constructor destd::unique_ptr
es explícito y, por lo tanto, es detallado regresarunique_ptr
de una función. Además, prefiero usarauto p = make_unique<foo>(bar, baz)
questd::unique_ptr<foo> p(new foo(bar, baz))
.make_unique
está llegandoC++14
, vea isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meetingRespuestas:
Herb Sutter, presidente del comité de estandarización de C ++, escribe en su blog :
También ofrece una implementación que es idéntica a la dada por el OP.
Editar:
std::make_unique
ahora es parte de C ++ 14 .fuente
make_unique
plantilla de función en sí misma no garantiza llamadas seguras de excepción. Se basa en la convención, que la persona que llama lo usa. En contraste, la estricta verificación de tipo estático (que es la diferencia principal entre C ++ y C) se basa en la idea de hacer cumplir la seguridad, a través de los tipos. Y para eso,make_unique
simplemente puede ser una clase en lugar de una función. Por ejemplo, vea el artículo de mi blog de mayo de 2010. También está vinculado a la discusión en el blog de Herb.make_unique
una clase, ahora creo que es mejor convertirla en una función que produzca unmake_unique_t
, la razón de esto es un problema con el análisis más perverso :-).make_unique
ofrece la garantía de una fuerte excepción. O tal vez está mezclando la herramienta con su uso, en cuyo caso ninguna función es segura. Considerevoid f( int *, int* ){}
, ofrece claramente lano throw
garantía, pero según su línea de razonamiento, no es una excepción segura, ya que puede ser mal utilizada. ¡Peor,void f( int, int ) {}
tampoco es una excepción segura !:typedef unique_ptr<int> up; f( *up(new int(5)), *up(new int(10)))
...make_unique
práctica como arriba y me apunto a un artículo de Sutter, el artículo que mi google-fu me señaló a los estados quemake_unique
ofrece la garantía fuerte excepción , lo que contradice su declaración anterior. Si tienes un artículo diferente, estoy interesado en leerlo. Entonces, mi pregunta original es ¿Cómo esmake_unique
(como se definió anteriormente) una excepción segura? (Nota: sí, creo que esomake_unique
mejora la seguridad de las excepciones en los lugares donde se puede aplicar)make_unique
. Primero, no veo cómo este es inseguro, y no veo cómo agregar un tipo adicional lo haría más seguro . Lo que sí sé es que estoy interesado en comprender los problemas que puede tener esta implementación, no puedo ver ninguno, y cómo una implementación alternativa los resolvería. ¿Cuáles son las convenciones quemake_unique
depende de? ¿Cómo usaría la verificación de tipo para hacer cumplir la seguridad? Esas son las dos preguntas para las que me encantaría recibir una respuesta.Agradable, pero Stephan T. Lavavej (mejor conocido como STL) tiene una mejor solución
make_unique
, que funciona correctamente para la versión de matriz.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 de C ++ 14.
fuente
make_unique
debe ir en un encabezado. Los encabezados no deben importar un espacio de nombres (vea el Artículo # 59 en el libro "Normas de codificación C ++" de Sutter / Alexandrescu). Los cambios de Xeo ayudan a evitar alentar malas prácticas.std::make_shared
no es solo taquigrafía parastd::shared_ptr<Type> 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, debido a questd::make_shared
asigna el objeto real, es posible questd::make_shared
asigne tanto el objeto como el bloque de seguimiento en el mismo bloque de memoria.Entonces, si bien
std::shared_ptr<Type> ptr = new Type(...);
serían dos asignaciones de memoria (una para elnew
, una en elstd::shared_ptr
bloque de seguimiento),std::make_shared<Type>(...)
asignaría un bloque de memoria.Eso es importante para muchos usuarios potenciales de
std::shared_ptr
. Lo único questd::make_unique
haría es ser un poco más conveniente. Nada más que eso.fuente
Si bien 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 queshared_ptr<T>(new T)
, que está asignado de manera diferente, y no hay forma de lograr esto sin el dedicado ayudante.SuCorrección: de hecho, esto no es cierto: tener una llamada de función para ajustar lamake_unique
envoltura, por otro lado, es un mero azúcar sintáctico alrededor de unanew
expresión, por lo que, aunque pueda parecer agradable a la vista, no aporta nadanew
a la mesa.new
expresión proporciona seguridad de excepción, por ejemplo, en el caso de que llame a una funciónvoid f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
. Tener dosnew
s sin procesar sin secuencia uno con respecto al otro significa que si una nueva expresión falla con una excepción, la otra puede perder recursos. En cuanto a por qué no haymake_unique
un estándar: simplemente se olvidó. (Esto sucede ocasionalmente. Tampoco hay unstd::cbegin
estándar 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 debería permitir; esto es diferente deshared_ptr
, que utiliza el borrado de tipos para almacenar eliminadores personalizados sin hacerlos parte del tipo.fuente
shared_ptr<T>(new T)
usa uno de ellos,make_shared<T>()
usa uno diferente. Permitir que sea una buena cosa, y la versión make-shared es, en cierto sentido, el puntero compartido más liviano que puedes obtener.shared_ptr
asigna un bloque de memoria dinámica para mantener el conteo y la acción de "eliminación" cuando crea unshared_ptr
. Si pasa el puntero explícitamente, necesita crear un "nuevo" bloque, si lo usamake_shared
puede agrupar su objeto y los datos del satélite en un solo bloque de memoria (unonew
) resultando en una asignación / desasignación más rápida, menos fragmentación y (normalmente ) mejor comportamiento de caché.En C ++ 11 también
...
se usa (en el código de la plantilla) para la "expansión del paquete".El requisito es que lo use como sufijo de una expresión que contiene un paquete de parámetros sin expandir, y simplemente aplicará la expresión a cada uno de los elementos del paquete.
Por ejemplo, basándose en su ejemplo:
El último es incorrecto, creo.
Además, el paquete de argumentos no se puede pasar a una función sin expandir. No estoy seguro acerca de un paquete de parámetros de plantilla.
fuente
std::forward<Args>(args)...
, que se expande aforward<T1>(x1), forward<T2>(x2), ...
.forward
realidad siempre requiere un parámetro de plantilla, ¿no?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:
fuente