Pregunta

Si uso la palabra clave new en mi biblioteca (que está construida de manera diferente a mi aplicación principal), cuando la elimino en mi aplicación principal con delete , ¿está ahí? ¿una posibilidad de que pueda tener un bloqueo / error?

¿Fue útil?

Solución

sí en verdad. En particular, verá que los problemas con los montones de depuración / liberación son diferentes, también si su biblioteca usa una ubicación nueva o cualquier montón personalizado tendrá un problema. Sin embargo, el problema de depuración / liberación es, con mucho, el más común.

Otros consejos

Depende. Si está hablando de una biblioteca estática, entonces probablemente estará bien: el código se ejecutará en el mismo contexto que el programa principal, utilizando la misma biblioteca de tiempo de ejecución 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 la DLL podría estar usando una biblioteca de tiempo de ejecución 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 la DLL (o viceversa) provocará (en el mejor de los casos) un bloqueo inmediato o (en el peor) daño de la memoria que provocará tómese un tiempo para localizarlo.

Tienes un par de opciones. El primero es utilizar el "método de fábrica". patrón para crear y eliminar estos objetos:

Foo *CreateFoo();
void DeleteFoo(Foo *p);

Estos no deben implementarse en el archivo de encabezado.

Alternativamente, puede definir un método Destroy en el objeto:

class Foo
{
    ~Foo();

public:
    virtual void Destroy();
};

... de nuevo, no implemente esto en el archivo de encabezado. Lo implementaría 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 Release que elimina el objeto cuando su recuento de referencia cae a cero.

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á el nuevo y devolverá un puntero, que luego se pasa a la función Eliminar para su eliminación.

Es un problema que solo he visto en Windows.

Los sistemas Unixish no tienen la costumbre 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 están utilizando la misma biblioteca del sistema para hacerlo.

Tengo que decir que este problema que Windows crea con sus diversas DLL de tiempo de ejecución de C es realmente molesto y poco natural para un programador de C. Mira la biblioteca C; tiene funciones como strdup que malloc la cadena y espera que el programador llame a free () en ella. Pero haga lo mismo en su propia biblioteca en Windows y espere la explosión. También tendrá que esperar, porque no sucederá durante el desarrollo, sino solo después de que haya entregado la DLL compilada a alguna otra savia pobre.

Old New Thing ha cubierto esto antes . También da una lista de las principales soluciones de Microsoft.

Tienes 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 eliminar 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 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 y cuando esas cuatro funciones miembro estén definidas en la misma DLL, cualquier clase que se derive de esta clase será automáticamente "segura para DLL". - new y delete se pueden usar normalmente en ellos sin preocuparse por los límites de DLL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top