¿Por qué no hay std::make_uniqueuna 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 newmuy 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::forwardcompilar 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_ptrtoma un segundo parámetro de plantilla que de alguna manera debería permitir, que es diferenteshared_ptr.make_uniquecon un Deleter costumbre, porque obviamente se asigna a través de llanura de edadnewy por lo tanto debe utilizar el viejo y simpledelete:)make_uniquese limitaría a lanewasignación ... bueno, está bien si quieres escribirla, pero puedo ver por qué algo así no es parte del estándar.make_uniqueplantilla ya que el constructor destd::unique_ptres explícito y, por lo tanto, es detallado regresarunique_ptrde una función. Además, prefiero usarauto p = make_unique<foo>(bar, baz)questd::unique_ptr<foo> p(new foo(bar, baz)).make_uniqueestá 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_uniqueahora es parte de C ++ 14 .fuente
make_uniqueplantilla 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_uniquesimplemente 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_uniqueuna 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_uniqueofrece 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 throwgarantí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_uniqueprá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_uniqueofrece 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_uniquemejora 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_uniquedepende 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_uniquedebe 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_sharedno 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_ptrdebe asignar un bloque de seguimiento además de mantener el almacenamiento para el puntero real. Sin embargo, debido a questd::make_sharedasigna el objeto real, es posible questd::make_sharedasigne 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_ptrbloque 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_uniqueharí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_uniqueenvoltura, por otro lado, es un mero azúcar sintáctico alrededor de unanewexpresión, por lo que, aunque pueda parecer agradable a la vista, no aporta nadanewa la mesa.newexpresió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 dosnews 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_uniqueun estándar: simplemente se olvidó. (Esto sucede ocasionalmente. Tampoco hay unstd::cbeginestándar global en el estándar aunque debería haber uno).También tenga en cuenta que
unique_ptrtoma 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_ptrasigna 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_sharedpuede 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), ....forwardrealidad 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