c++ - smart - ¿Cómo pasar deleter a make_shared?
unique pointer (4)
A partir de la documentation , make_shared
acepta una lista de argumentos con los que se construirá una instancia de T.
Además, la documentación dice que:
Esta función se usa normalmente para reemplazar la construcción std :: shared_ptr (nueva T (args ...)) de un puntero compartido desde el puntero sin formato devuelto por una llamada a new.
Debido a eso, puede deducir que no puede configurar un borrado personalizado.
Para hacer eso, debes crear el shared_ptr
por ti mismo por medio del constructor correcto.
Como ejemplo de un constructor de la lista propuesta, puede usar:
template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );
Así, el código será algo así como:
auto ptr = std::shared_ptr(new MyClass{arg1, arg2}, myDeleter);
En lugar de:
auto ptr = std::make_shared<MyClass>(arg1, arg2);
Desde C ++ 11, debido a varias razones, los desarrolladores tienden a usar clases de puntero inteligente para objetos dinámicos de por vida. Y con esas nuevas clases de puntero inteligente, los estándares, incluso sugieren no usar operadores como new
lugar de eso, sugieren usar make_shared
o make_unique
para evitar algunos errores propensos.
Si nos gusta usar una clase de puntero inteligente, como shared_ptr
, podemos construir una como
shared_ptr<int> p(new int(12));
También nos gustaría pasar un borrado personalizado a las clases de puntero inteligente,
shared_ptr<int> p(new int(12), deleter);
Por otro lado, si nos gusta usar make_shared
para asignar, por ej. int
, en lugar de usar el constructor new
y shared_ptr
, como en la primera expresión anterior, podemos usar
auto ip = make_shared<int>(12);
Pero, ¿qué pasa si también nos gusta pasar un borrado personalizado a make_shared
, hay una forma correcta de hacerlo? Parece que los compiladores, al menos gcc, da un error a,
auto ip = make_shared<int>(12, deleter);
Como han dicho otros, make_shared
no se puede utilizar con un eliminador personalizado. Pero quiero explicar por qué.
Existen eliminaciones personalizadas porque asignó el puntero de alguna manera especial y, por lo tanto, necesita poder asignarlo de manera correspondiente. Bueno, make_shared
asigna el puntero con el new
. Los objetos asignados con new
deben ser desasignados con delete
. Lo que el estándar deleter obedientemente hace.
En resumen, si puede vivir con el comportamiento de asignación predeterminado, también puede vivir con el comportamiento de desasignación predeterminado. Y si no puede vivir con el comportamiento de asignación predeterminado, debe usar allocate_shared
, que utiliza el asignador proporcionado para asignar y desasignar el almacenamiento.
Además, se permite que make_shared
(y casi con toda seguridad) asigne la memoria para T
y el bloque de control para shared_ptr dentro de la misma asignación. Esto es algo que su eliminador no puede realmente saber o tratar. Considerando que allocate_shared
es capaz de manejarlo, ya que el asignador que proporcionas puede realizar tareas de asignación y desasignación.
No se especifica cómo make_shared
obtiene la memoria para el objeto (podría usar el operator new
o malloc
o algún tipo de asignador), por lo que no hay forma de que un eliminador personalizado pueda saber cómo hacer lo correcto. make_shared
crea el objeto, por lo que también debes confiar en él para destruirlo correctamente y hacer la limpieza adecuada, sea lo que sea.
También nos gustaría pasar un borrado personalizado a las clases de puntero inteligente,
shared_ptr<int> p(new int(12), deleter);
No creo que este sea un ejemplo muy realista. Un eliminador personalizado se usa normalmente cuando el recurso se obtuvo de alguna manera especial. Si acaba de crearlo con algo así, ¿por qué necesita un eliminador personalizado de todos modos?
Si solo quieres que un código se ejecute en la destrucción, ¡ponlo en un destructor! De esa manera también puedes usarlo con make_shared
por ejemplo.
struct RunSomethingOnDestruction {
RunSomethingOnDestruction(int n) : i(n) { }
~RunSomethingOnDestruction() { /* something */ }
int i;
};
auto px = std::make_shared<RunSomethingOnDestruction>(12);
std:shared_ptr<int> p(px, px->i);
Esto le da un shared_ptr<int>
que se crea con make_shared
(para que obtenga las optimizaciones de memoria hechas por make_shared
) que ejecutará algún código personalizado en la destrucción.
Usted no puede make_shared<T>
reenvía los argumentos proporcionados al constructor de tipo T
Se usa para el caso simple cuando se desea el borrado predeterminado.