¿Corrupción del puntero C++?

Para ser honesto, no sé si el título es correcto para el problema que estoy experimentando. El asunto es así. Tengo una clase llamada Engine, de la cual hay una instancia.

Contiene dos variables miembro (entre otras) llamadas testTexture, un ejemplo de mi costumbre Texture clase, y testObject, una instancia de mi clase de objeto personalizado.

En la función Motor Init sus valores se establecen así:

testTexture = Texture(0, TEXT("D:\\spriteWallVertical112.png"),
                      renderer.ReturnDevice());
testObject = Object(0,testTexture.textureID, D3DXVECTOR3(0,0,0),
                    D3DXVECTOR3(100,100,100), testTexture.texture, &renderer);

Todo esto parece funcionar como me gustaría, sus valores se almacenan y parecen mantenerse bien.

Sin embargo, dentro del Object constructor de clase hay una llamada a una función en mi Renderer clase llamada AddNewTextureObject:

rendererPointer->AddNewTextureObject(&objectID, &textureID, textureInput, 
                                     &origin, &coordinates);

Esto parece funcionar bien, pero a medida que el programa ejecuta los valores, los punteros parecen sobrescribirse a medida que avanza el programa. No se convierten instantáneamente en memoria basura, pero parece claro que lo son. Puedo proporcionar el código según sea necesario, pero no quiero simplemente enviar spam a esta pregunta con un código que no es relevante para la pregunta, especialmente si alguien más puede ver algo obvio que estoy haciendo mal.

Sin embargo, publicaré el TextureObject código de clase por ahora, ya que creo que es el más relevante aquí:

#ifndef TEXTUREOBJECT_H
#define TEXTUREOBJECT_H
#ifndef UNICODE
#define UNICODE
#endif

#include <d3dx9.h>

class TextureObject
{
public:
    TextureObject();
    TextureObject(unsigned int *, int *, LPDIRECT3DTEXTURE9, D3DXVECTOR3 *, D3DXVECTOR3 *);
    ~TextureObject();

    unsigned int *objectID; // The object with the texture.  Use this for locating and deleting this instance of TextureObject.
    int *textureID;
    LPDIRECT3DTEXTURE9 texture; // May not be needed if we can simply select the texture via ID.
    const D3DXVECTOR3 *origin; // Needed for drawing rotations....I think.
    D3DXVECTOR3 *coordinates;
    int maintainMe;
};
#endif

La variable maintainMe mantiene su valor si se lo asigno.

Este es el código para el AddNewTextureObject() función:

void Renderer::AddNewTextureObject(unsigned int *objectIDInput, int *textureIDInput, LPDIRECT3DTEXTURE9 textureInput, D3DXVECTOR3 *originInput, D3DXVECTOR3 *coordinatesInput)
{
    //testTextureObject = TextureObject(objectID, textureID, textureInput, originInput, coordinatesInput);
    testTextureObject.objectID = objectIDInput;
    testTextureObject.textureID = textureIDInput;
    testTextureObject.texture = textureInput;
    testTextureObject.origin = originInput;
    testTextureObject.coordinates = coordinatesInput;
    testTextureObject.maintainMe = 3067;

Tenga en cuenta que cualquiera de los métodos de asignación de valores a testTextureObject resultados en el problema.

Cualquier ayuda con esto será muy apreciada.

EDIT:

Aquí está el constructor para el Object clase:

Object::Object(unsigned int objectIDInput, int textureIDInput, D3DXVECTOR3 originInput, D3DXVECTOR3 coordinatesInput, LPDIRECT3DTEXTURE9 textureInput, Renderer *rendererInput)
{
    objectID = objectIDInput;
    textureID = textureIDInput;
    origin = originInput;
    coordinates = coordinatesInput;
    rendererPointer = rendererInput;
    rendererPointer->AddNewTextureObject(&objectID, &textureID, textureInput, &origin, &coordinates);
}

Se declara en Object.h en la Object clase como público así:

Object(unsigned int, int, D3DXVECTOR3, D3DXVECTOR3, LPDIRECT3DTEXTURE9, Renderer *);

EDIT2: hice un constructor de copia y un operador de asignación:

Object::Object(const Object &source)
{
    objectID = source.objectID;
    textureID = source.textureID;
    texture = source.texture;
    origin = source.origin;
    coordinates = source.coordinates;
    rendererPointer = source.rendererPointer;
}

Object& Object::operator=(const Object &source)
{
    if(this == &source)
    {
        return *this;
    }

    objectID = source.objectID;
    textureID = source.textureID;
    texture = source.texture;
    origin = source.origin;
    coordinates = source.coordinates;
    rendererPointer = source.rendererPointer;

    return *this;
}

¿Les parecen correctos a las personas más experimentadas? Desafortunadamente, esto por sí solo no parece solucionar el problema.

preguntado el 04 de julio de 12 a las 00:07

¿Hay alguna razón por la que está pasando referencias pero los argumentos del método son punteros? Creo que hay casos de uso para ambos por separado, pero ¿por qué mezclarlos? -

Me temo que no entiendo muy bien lo que quieres decir. Un puntero es una referencia, ¿no? -

En su Engine's Init función, qué está pasando exactamente con esos Texture y Object ¿instancias? ¿Los está creando accidentalmente en la pila, no los está almacenando permanentemente, haciendo que desaparezcan cuando Init se completa y se quedan con punteros/referencias pendientes? -

Ambos testTexture y testObject son variables miembro de la Engine clase. El motor se crea en main, por lo que no creo que nada esté fuera de alcance. los valores de testTexture y testObject parecen mantener los valores que deberían. Son solo las cosas en testTextureObject eso parece ir mal. -

@Interminable un puntero no es una referencia. Una referencia es un alias. Puede crear una referencia a un puntero o un puntero a una referencia, pero su semántica es diferente. -

1 Respuestas

Dado que define un destructor y tiene punteros en su TextureObject clase, debe seguir la regla de 3: defina un destructor, un constructor de copias y un operador de asignación. Parece que los punteros pueden haberse originado a partir de Object, por lo que es posible que deba hacer lo mismo para esa clase también.

Me imagino que el problema al que se enfrenta es un problema de puntero colgante, ya que después de la inicialización de testObject, el temporal utilizado para inicializarlo se destruye y libera los punteros que se inicializaron dentro de él. Por lo tanto, testTextureObject ahora tiene punteros a la memoria liberada (porque esos punteros provienen originalmente del temporal).

Edit: Basado en el constructor de Object, vemos eso rendererPointer->AddNewTextureObject se están pasando punteros de la actual Object instancia, que sería la temporal.

testObject = Object(0,testTexture.textureID, D3DXVECTOR3(0,0,0),
                    D3DXVECTOR3(100,100,100), testTexture.texture, &renderer);

Esta línea de código crea una instancia temporal de Objecty luego usa el operador de asignación para inicializar testObject. Después de esta línea de código, el temporal sería destruido. Ahora renderer está sosteniendo un TextureObject que se inicializa en punteros de un temporal que ya no existe.

Edit: Parece que tienes cierta confusión sobre el problema que la regla de 3 está tratando de ayudarte a resolver. Puedes leer el la respuesta aceptada a la pregunta sobre la regla de 3. Pero para darte un ejemplo simple, solo considera el problema simple de una clase que asigna memoria.

class Foo {
    Bar *bar;
public:
    Foo () : bar(new Bar) {}
    ~Foo () { delete bar; }
    Bar * get_bar () { return bar; }
};

Se requiere el destructor para no perder memoria. Sin embargo, se presentan problemas si se utiliza el constructor de copia o el operador de asignación.

Foo a;
Foo b(a); // copy

El problema con b es que tiene el mismo puntero que a. Así que cuando b y a se destruyen, el puntero se eliminará dos veces.

Foo a;
Foo c;
c = a;    // assign

El problema con c es que no solo tiene el mismo puntero que a (lo que conducirá a una doble eliminación), pero cualquier memoria que haya creado en su constructor ahora se ha filtrado.

La regla de 3 es: si se necesita un destructor, entonces también se necesita un constructor de copia y un operador de asignación. El propósito de la regla es hacer que el desarrollador piense en los problemas que deben resolverse al agregar un destructor, y qué consecuencias tendrían para las construcciones y asignaciones de copias, y crear una solución razonable.

En tu caso, renderer está sosteniendo un TextureObject creado por el temporal Object. Debe pensar en cómo solucionar la situación, ya sea en el destructor, el constructor de copias y el operador de asignación de Object, o evitando el problema con alguna otra solución.

contestado el 23 de mayo de 17 a las 11:05

Por lo tanto, la necesidad de usar una nueva textura (...) y un nuevo objeto (...) en lugar de los objetos asignados a la pila que usó. - julien lebot

@ LeSnip3R: O un constructor de copia/operador de asignación adecuado que hizo una copia profunda. - jxh

Mhhh, desafortunadamente, no creo que eso ayude a resolver su problema (aunque es un buen consejo de programación). Vea que el problema ocurre en el constructor de Object, y creo que toma algunos de los parámetros por valor (mirando el D3DXVECTOR en particular). Por lo tanto, para AddNewTextureObject estaría pasando punteros a objetos locales y ahí es probablemente donde las cosas se ponen feas. Tener un constructor de copia no ayudaría allí. - julien lebot

@LeSnip3R: Necesita un constructor de copias para Object también. - jxh

@LeSnip3R: Si dice que no tenemos suficiente información para resolver completamente su problema, estoy de acuerdo. Pero creo que hemos identificado la causa de su problema, y ​​debería poder resolverlo por sí mismo ahora que sabe dónde buscar. - jxh

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.