2010-01-12 8 views
5

Tengo una pregunta interesante sobre los punteros de C++.¿Cómo reasignar el puntero `this` dentro de la función miembro miembro?

Probablemente piense que tengo que cambiar mi diseño, y evite haciendo lo que estoy haciendo, y probablemente tenga razón. Pero supongamos que tengo una buena razón para hacerlo a mi manera.

Así que esta es la situación. Tengo un C++ TestClass clase, y tengo un puntero A de este tipo:

TestClass* A = new TestClass(); 

Entre otras cosas TestClass tiene esta función:

void TestClass::Foo(){ 
    TestClass* B = new TestClass(); 
    ... 
} 

Esta función crea el objeto B del mismo tipo y puebla con algunos datos.

Al final de esta función, quiero puntero del A al punto B. al objeto en cualquier lugar fuera de esta función se vería como A=B; dentro de esta función podría verse como this = B
Pero como usted sabe, no puede reasignar este puntero.

soluciones posibles:

  1. copiar la memoria:

    memcpy(this, B, sizeof(TestClass)); 
    

    Este método funciona correctamente. La función copia cada bit del objeto B en el objeto A.
    Problema: si TestClass es un objeto grande (y lo es), crea una sobrecarga significativa en el rendimiento para múltiples llamadas Foo.

  2. devolver un puntero B de la función y hacer algo como esto

    Temp = A; 
    A=A->Foo(); 
    freeMemory(Temp); 
    

    Pero este código es estúpida, y hace que la función Foo muy difícil de usar.

Entonces la pregunta es, cómo puedo hacer this = B desde el interior de una función miembro, sin copiar objetos enteros?

+6

No creo que haya una buena razón para hacer esto. – GManNickG

+0

Todo esto huele mal. ¿Es Foo() realmente un método de clonación? ¿Por qué Foo() no se llama Clone() y devuelve un puntero al objeto recién creado? –

+2

¿Por qué necesita asignar un nuevo objeto? ¿Por qué no puedes simplemente sobrescribir/restablecer todos los miembros de A? –

Respuesta

7

cómo puedo hacer esto = B

No se puede.

Una de las soluciones de trabajo: memcpy (esto, B, sizeof (TestClass)); este método funciona correctamente.

Si TestClass no es un POD, esta función no funciona. No puede memcpy objetos con funciones virtuales, por ejemplo. Va a volar el vtable.

+0

El puntero vtable no es un gran problema (ya que es inmutable para un tipo concreto) , pero cualquier otra referencia que necesite un manejo especial es, en términos generales, cualquier cosa que necesite un Copy CTor (teniendo en cuenta la regla "si necesita una, necesita las tres"). – peterchen

2

El problema es que muchos punteros, no solo A, pueden apuntar al objeto anterior.Este puntero no es A, aunque A contiene una copia de él. La única manera de hacerlo es 1. reasignar A, o 2. crear un nuevo tipo de puntero que agregue un nivel de indirección a su objeto para que pueda reemplazarlo sin que nadie lo sepa.

0

Estoy bastante seguro de que debe mirar punteros inteligentes como una forma de resolver este problema. Básicamente, estos agregan un nivel adicional de direccionamiento indirecto (sin cambiar el uso de los clientes de sintaxis), y le permiten cambiar el objeto real al que se apunta sin informar al cliente.

4

No puede. this está definido por el estándar como TestClass * const.

Para comprender por qué, piense en este código:

int main() { 
    TestClass A; 
    A.Foo(); 
    return 0; 
} 

A está en la pila. ¿Cómo haces que un objeto en la pila se "refiera" a otra cosa?

13

Utilice un nivel adicional de direccionamiento indirecto. Su TestClass puede tener un puntero que apunta a una clase que contiene todos sus datos.

class TestClass 
{ 
private: 
    TestClassData* m_data; 

}; 

void TestClass::Foo() 
{ 
    TestClassData* B = new TestClassData(); 
    ... 
    delete m_data; 
    m_data = B; 
} 

Sólo asegúrese de que sus operator== devuelve verdadero si el contenido de M_DATA son iguales.

+2

Creo que esta es la manera más elegante de hacerlo si su objetivo es minimizar la copia de datos. –

+2

"Cualquier problema en la informática puede resolverse agregando otra capa de abstracción" - (desearía poder recordar dónde lo había visto) – FrustratedWithFormsDesigner

+0

@FrustratedWithFormsDesigner: . Se cree ampliamente que Stroustrup lo dijo, pero citó a David J. Wheeler. – unwind

1

Lo que estás haciendo no es bueno.

En primer lugar, usted tiene la función Foo que será:

  • Crear y generar una nueva clase
  • Reasignar una clase existente a la nueva clase

Así que, ¿por qué no cambiar el clase existente en la clase que quieres?

Dicho esto, se puede hacer Foo estática y tome "tomar this manualmente":

void Foo(TestClass*& this) 
{ 
    delete this; 
    this = // ... 
} 

Pero eso es igual de desagradable como sus otras soluciones. Probablemente necesitemos más contexto para darle la mejor solución.

5

interior de su función, que puede hacer

*this = B; 

que hacen prácticamente la misma operación de copia.
O también se podría declarar

Foo(TestClass &X); 

y reasignar la dirección X en el interior.

Cuestiones relacionadas