2010-12-17 17 views
6

Estoy portando algún código a Windows y estoy perplejo. Hay un código que se ejecuta automáticamente al iniciarse para copiar un puntero a un puntero y se ejecuta nuevamente al salir para eliminar el puntero a un puntero si no es nulo.El puntero a puntero se bloquea en caso de que el puntero no

He creado un programa de ejemplo para reproducir el comportamiento

int main() 
{ 
    // Pointer to a Pointer, current crash. 
    InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 
    delete *ptrptr; // Crash here. 

    // Single pointer, works fine. 
    InterfaceClass* ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = object; 
    delete ptrptr; 

    // There are other cases where there are only 3 classes in the hierarchy. 
    // This also works fine. 
    InterfaceClass** ptrptr; 
    ConcreteOne* object = new ConcreteOne(); 
    ptrptr = (InterfaceClass**)(&object); 
    delete *ptrptr; 

    return 0; 
} 

la jerarquía de clases es el siguiente. La clase base es una interfaz con algunas funciones virtuales puras y está incluida en muchas clases en todo el programa de tal manera que muchos objetos potencialmente la heredan de más de un lugar. Debido a esto, la implementación concreta debe ampliarse con "InterfaceClass virtual pública". En este ejemplo, eliminar el "virtual" resuelve el bloqueo.

class InterfaceClass { 
public: 
    virtual ~InterfaceClass() {}; 
    InterfaceClass() {} 
}; 

class ConcreteClass : public virtual InterfaceClass { 
public: 
    ConcreteClass() { } 
    virtual ~ConcreteClass() {} 
}; 

class ConcreteOne : public ConcreteClass 
{ 
public: 
    ConcreteOne(void) {} 
    virtual ~ConcreteOne(void) {} 
}; 

class ConcreteTwo : public ConcreteOne 
{ 
public: 
    ConcreteTwo(void) {} 
    virtual ~ConcreteTwo(void) {} 
}; 

Respuesta

5

Así que está usted familiarizado con el hecho de que el tipo de un puntero casi no tiene nada que ver con el tipo que apunta a? En otras palabras, ¿tiene la impresión de que si T1 hereda de T2, T1 * también hereda de T2 *? Eso sería un error Ahora, ¿cómo se aplica eso a tu situación actual?

InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 

Aquí hay un problema importante con la fundición de estilo C. Aceptar, por lo que ahorra algo de espacio horizontal, pero cuando se entera con qué tipo de yeso que acabas de hacer? No es lo que crees que es. En realidad se realizó una reintpret_cast de tipo ConcreteTwo * InterfaceClass a un tipo relacionado *! Ahora la dirección del puntero no tiene nada que ver con el tipo que dice que es.

Entonces le pase un tipo de puntero en reinterpretados de eliminación, que rápidamente causó que viola su propio esfínter.

3

Bueno, el compilador se advirtió, se decidió a hacerlo a tu manera ...

No se puede hacer este reparto:

ptrptr = (InterfaceClass**)(&object); 

PORQUE object puntos a ConcreteTwo, que no es lo mismo que InterfaceClass. InterfaceClass subobjeto de ConcreteTwo está ubicado en una dirección diferente. *ptrptr no es un puntero a la instancia de InterfaceClass.

El puntero que pase a delete es un puntero a ConcreteTwo, pero le dijo al compilador que es un puntero a InterfaceClass. delete supone que es de hecho un InterfaceClass, de ahí el bloqueo.

1

Creo que el problema se encuentran en las líneas del elenco. Por cierto, si quitas el yeso que insertaste, el compilador te dice cuál es el problema.

Si realmente quieres hacer esto, manera, que muy encarecidamente, primero debe crear un temporal:

ConcreteTwo* object = new ConcreteTwo(); 
InterfaceClass* ptr = object; 

, entonces puede tomar su dirección y asignarlo a la variable ptrptr:

InterfaceClass** ptrptr = &ptr; 

ahora puede eliminar con seguridad:

delete *ptrptr; 

Tenga en cuenta que si ptr queda fuera del alcance antes de ptrptr, la eliminación probablemente se bloqueará nuevamente.

En cuanto al resto, Noah le explica por qué su código no funciona.

Cuestiones relacionadas