¿ std::make_unique
Tiene algún beneficio de eficiencia como std::make_shared
?
En comparación con la construcción manual std::unique_ptr
:
std::make_unique<int>(1); // vs
std::unique_ptr<int>(new int(1));
c++
c++11
c++14
smart-pointers
unique-ptr
NFRCR
fuente
fuente
make_shared
Tiene alguna eficiencia sobre solo escribir el código de mano larga?make_shared
puede asignar tanto el espacio para el objeto como el espacio para el bloque de control juntos en una sola asignación. El costo de esto es que el objeto no se puede desasignar por separado del bloque de control, por lo que si usaweak_ptr
mucho, puede terminar usando más memoria.Respuestas:
La motivación detrás
make_unique
es principalmente doble:make_unique
es seguro para crear temporarios, mientras que con el uso explícitonew
debe recordar la regla sobre no usar temporarios sin nombre.La adición de
make_unique
finalmente significa que podemos decirle a la gente que 'nunca' use ennew
lugar de la regla anterior a "nunca" usar,new
excepto cuando realice ununique_ptr
".También hay una tercera razón:
make_unique
no requiere uso de tipo redundante.unique_ptr<T>(new T())
->make_unique<T>()
Ninguno de los motivos implica mejorar la eficiencia del tiempo de ejecución de la manera en que lo
make_shared
hace (debido a evitar una segunda asignación, a costa de un uso de memoria pico potencialmente mayor).* Se espera que C ++ 17 incluya un cambio de regla que significa que esto ya no es inseguro. Véanse los documentos del comité C ++ P0400R0 y P0145R3 .
fuente
std::unique_ptr
ystd::shared_ptr
es por eso que podemos decirle a la gente que "nunca lo usenew
".make_shared
y también lomake_unique
es la pieza final que faltaba anteriormente.f
:f(unique_ptr<T>(new T), function_that_can_throw());
- citar la respuesta: El compilador se le permite a la llamada (en orden):new T
,function_that_can_throw()
,unique_ptr<T>(...)
. Obviamente, si enfunction_that_can_throw
realidad tira, entonces goteas.make_unique
Previene este caso. Entonces, mi pregunta está respondida.std::make_unique
ystd::make_shared
están ahí por dos razones:std::unique_ptr
ostd::shared_ptr
constructores. (Vea la sección de Notas aquí .)No se trata realmente de la eficiencia del tiempo de ejecución. Hay un poco sobre el bloque de control y la
T
asignación de todos a la vez, pero creo que eso es más una bonificación y menos una motivación para que estas funciones existan.fuente
std::make_shared
asegurará que al menos uno de ellos quede envuelto en el puntero inteligente antes de que ocurra la otra asignación de memoria, por lo tanto, no habrá fugas.Una razón por la que tendría que usar
std::unique_ptr(new A())
ostd::shared_ptr(new A())
directamente en lugar destd::make_*()
no poder acceder al constructor de la claseA
fuera del alcance actual.fuente
Considerar llamada de función
Supongamos que lo nuevo
A()
tiene éxito, pero lo nuevoB()
arroja una excepción: lo detecta para reanudar la ejecución normal de su programa. Desafortunadamente, el estándar C ++ no requiere que el objeto A se destruya y se desasigne su memoria: la memoria se pierde silenciosamente y no hay forma de limpiarla. Al envolver A y B enstd::make_uniques
usted, está seguro de que no ocurrirá la fuga:El punto aquí es que
std::make_unique<A>
ystd::make_unique<B>
ahora son objetos temporales, y la limpieza de los objetos temporales está especificada correctamente en el estándar C ++: sus destructores se activarán y se liberará la memoria. Entonces, si puede, siempre prefiera asignar objetos usandostd::make_unique
ystd::make_shared
.fuente