He escrito un contenedor de C ++ extensible alrededor de una biblioteca c muy difícil de usar pero también muy útil. El objetivo es tener la conveniencia de c ++ para asignar el objeto, exponer sus propiedades, desasignar el objeto, copiar semántica, etc.
El problema es este: a veces la biblioteca c quiere el objeto subyacente (un puntero al objeto), y el destructor de clase no debe destruir la memoria subyacente. Si bien la mayoría de las veces, el destructor debe desasignar el objeto subyacente. He experimentado con la configuración de un bool hasOwnership
indicador en la clase para que el destructor, el operador de asignación, etc. sepan si debe o no liberar la memoria subyacente. Sin embargo, esto es engorroso para el usuario y, a veces, no hay forma de saber cuándo otro proceso usará esa memoria.
Actualmente, lo tengo configurado donde cuando la asignación proviene de un puntero del mismo tipo que el tipo subyacente, entonces configuro el indicador hasOwnership. Hago lo mismo cuando se llama al constructor sobrecargado usando el puntero de la biblioteca c. Sin embargo, esto todavía no maneja el caso cuando el usuario ha creado el objeto y lo ha pasado a una de mis funciones que llama a c_api y la biblioteca almacena el puntero para su uso posterior. Si eliminaran su objeto, sin duda causaría un defecto en la biblioteca c.
¿Existe un patrón de diseño que simplifique este proceso? ¿Quizás algún tipo de recuento de referencias?
fuente
unique_ptr
en la mayoría de los casos, ya puede manejar este tipo de recursos, por lo que no necesita implementar la administración de recursos usted mismo.unique_ptr
utiliza elrelease
método para renunciar a la propiedad del objeto almacenado.Respuestas:
Si la responsabilidad de limpiar las cosas asignadas dinámicamente cambia entre su clase de contenedor y la biblioteca C en función de cómo se usan las cosas, está tratando con una biblioteca C mal diseñada o está tratando de hacer demasiado en su clase de contenedor.
En el primer caso, todo lo que puede hacer es realizar un seguimiento de quién es responsable de la limpieza y esperar que no se cometan errores (ni usted ni los encargados del mantenimiento de la biblioteca C).
En el segundo caso, debe repensar el diseño de su envoltorio. ¿Todas las funciones pertenecen juntas en la misma clase, o se pueden dividir en varias clases? Quizás la biblioteca C usa algo similar al patrón de diseño de Fachada y debería mantener una estructura similar en su contenedor C ++.
En cualquier caso, incluso si la biblioteca C es responsable de limpiar algunas cosas, no hay nada de malo en mantener una referencia / puntero a esas cosas. Solo necesita recordar que no es responsable de limpiar a qué se refiere el puntero.
fuente
A menudo puedes usar un patrón como este:
Al usarlo
release
puede transferir explícitamente la propiedad. Sin embargo, esto es confuso y debe evitarlo si es posible.La mayoría de las bibliotecas de C tienen un ciclo de vida de objeto similar a C ++ (asignación de objetos, accesores, destrucción) que se asigna muy bien al patrón de C ++ sin transferencia de propiedad.
Si los usuarios necesitan propiedad compartida, deberían usarla
shared_ptr
con sus clases. No intentes implementar ninguna propiedad compartiéndote.Actualización: si desea que la transferencia de propiedad sea más explícita, puede usar un calificador de referencia:
Luego, los usuarios deben invocar
bar
valores como este:fuente
unique_ptr
, ya no almacena el puntero que tenía. Modelar la transferencia de propiedad y, al mismo tiempo, permitir el acceso a recursos desposeídos parece ser bastante confuso para los usuarios. ¿Cómo se controla cuando la biblioteca C libera los objetos que ahora posee?Hay una respuesta directa a su problema, punteros inteligentes. Al usar un puntero inteligente para mantener la memoria de la biblioteca C y agregar una referencia cuando el puntero también está en la biblioteca (y soltar la referencia cuando la biblioteca C vuelve), liberará automáticamente la memoria cuando el recuento de referencia caiga a cero (y sólo entonces)
fuente
Si la biblioteca puede liberar cosas internamente, y los escenarios donde esto puede suceder están bien documentados, entonces todo lo que puede hacer es establecer una bandera como ya lo está haciendo.
fuente