library - C++ mezclar nuevo/eliminar entre libs?
graphics c++ library (6)
Si utilizo la new
palabra clave en mi biblioteca (que se construye de forma diferente a mi aplicación principal), cuando la elimino en mi aplicación principal con delete
, ¿hay alguna posibilidad de que se produzca un bloqueo / error?
si realmentey. En particular, usted ve que los problemas con los montones de depuración / liberación son diferentes, y si su biblioteca utiliza la ubicación nueva o cualquier montón personalizado, tendrá un problema. El problema de depuración / liberación es, con mucho, el más común.
Depende. Si está hablando de una biblioteca estática, entonces probablemente esté bien: el código se ejecutará en el mismo contexto que el programa principal, utilizando la misma biblioteca de tiempo de ejecución de C ++. Esto significa que new
y delete
usarán el mismo montón.
Si está hablando de una biblioteca compartida (una DLL), entonces probablemente no estará bien. El código que se ejecuta en el archivo DLL puede estar utilizando una biblioteca de tiempo de ejecución de C ++ diferente, lo que significa que el diseño del montón será diferente. La DLL podría estar usando un montón diferente por completo.
Llamar a delete
(en el programa principal) en un puntero asignado por el DLL (o viceversa) conducirá a (en el mejor de los casos) un bloqueo inmediato o (en el peor de los casos) daños en la memoria que llevará un tiempo rastrear.
Tienes un par de opciones. El primero es usar el patrón de "método de fábrica" para crear y eliminar estos objetos:
Foo *CreateFoo();
void DeleteFoo(Foo *p);
Esto no debería implementarse en el archivo de encabezado.
Alternativamente, puede definir un método Destroy
en el objeto:
class Foo
{
~Foo();
public:
virtual void Destroy();
};
... otra vez, no implemente esto en el archivo de encabezado. Lo implementarías así:
void Foo::Destroy()
{
delete this;
// don''t do anything that accesses this object past this point.
}
Tenga en cuenta que el destructor para Foo es privado, por lo que debe llamar a Foo::Destroy
.
Microsoft COM hace algo similar, donde define un método de Release
que elimina el objeto cuando su recuento de referencia cae a cero.
Es un problema que solo he visto en Windows.
Los sistemas Unixish no tienen el hábito de obligar a las bibliotecas compartidas a vincularse a diferentes versiones de la misma biblioteca dentro del mismo programa y todos los símbolos cargados son visibles globalmente. Eso significa que si un objeto se asigna en una parte del código y se elimina en otra, ambos utilizan la misma biblioteca del sistema para hacerlo.
Tengo que decir que este problema que Windows crea con sus varias DLL C runtime es realmente molesto y antinatural para un programador de C. Mira la biblioteca C; tiene funciones como strdup que malloc la cadena y esperan que el programador llame gratis () sobre ella. Pero haga lo mismo en su propia biblioteca en Windows y simplemente espere la explosión. Tendrás que esperar, también, porque no ocurrirá durante el desarrollo, sino solo después de que hayas dado la DLL compilada a alguna otra pobre savia.
Sí lo harás. Una solución simple es proporcionar funciones Crear y Eliminar en su biblioteca a las que se pueda llamar desde la aplicación principal. La función Crear realizará la nueva y devolverá un puntero, que luego se pasará a la función Eliminar para su eliminación.
Tiene toda la razón de que hay un problema allí, pero para la mayoría de los casos hay una solución aún más simple que las otras respuestas (hasta ahora) han propuesto. Puede continuar usando new y delete libremente; todo lo que necesita hacer es sobrecargar new y delete para cada clase en su biblioteca que pueda usarse a través de los límites de la DLL.
Personalmente, acabo de definir una clase simple para proporcionar la funcionalidad necesaria:
class NewDelete
{
public:
void *operator new (size_t size);
void operator delete (void *memory);
void *operator new (size_t size, void *ptr);
void operator delete (void *memory, void *ptr);
};
Siempre que esas cuatro funciones miembro estén todas definidas en la misma DLL, cualquier clase que derive de esta clase será automáticamente "segura para las DLL". Las nuevas y eliminadas se pueden usar normalmente en ellas sin preocuparse por los límites de la DLL.
Old New Thing ha cubierto esto antes. También da una lista de las principales soluciones de Microsoft.