2011-12-20 15 views
12

Soy un poco nuevo en C++ y he estado haciendo programación en Obj-C y Java hasta ahora.C++: sobre gestión de memoria

decir que tengo una clase:

class Person { 

private: 
    Wife *current_wife; 
    //..... 
}; 

Así OBV I necesidad de implementar un método de selección para cambiar la variable de instancia esposa.

De esta manera:

Person::SetCurrentWife (Wife *new_wife) { 

    current_wife = new_wife; 
} 

Eso sería una copia shalllow.

Así que en algún lugar del bucle principal o algo que llamo:

Person *some_person = new Person(); 
... 
Wife *wife = new Wife(); 
some_person->SetCurrentWife(wife); 

Así que estoy confundido: ¿habrá una pérdida de memoria en esta lista? ¿Debo eliminar el objeto esposa aquí o en el destructor de la persona? En Obj-C liberaría a la esposa actual y luego enviaría un mensaje de retención a la esposa del objeto anterior, pero ¿cuál es la forma correcta de hacer métodos setter en C++?

+10

Dado que eres nuevo en C++, sigue este consejo: nunca uses 'new',' delete' o punteros. Como excepción, * puede * usar 'new' dentro del constructor de un puntero inteligente, pero solo después de haber determinado que realmente necesita almacenamiento dinámico. –

+4

Kerrek se olvidó de recomendar [un buen libro introductorio de C++] (http://stackoverflow.com/q/388242/46642) :) –

+4

En OO no necesita un setter, necesita funciones para dejar que el objeto haga algo (divorcio, nuevo casamiento). Los setters pueden ser convenientes, no son obvios. – stefaanv

Respuesta

4

Debe usar un puntero inteligente.

Si usa el puntero regular, ¡tenga cuidado!

Debe delete el miembro antiguo current_wife tanto en el destructor como en el método set. Configurar una nueva esposa dará lugar a la pérdida de memoria de la anterior, ya que el puntero a esa memoria asignada se pierde (a menos que administre la memoria fuera de la clase - vea abajo).

Pero incluso si lo hace, debe asegurarse de que nadie fuera de la clase pueda eliminar el miembro. Debe decidir si la gestión de la memoria se deja a la clase o se envía al exterior de la clase, y se adhiere a ella.

+3

-1 porque es simplemente un mal consejo. Me sorprendería mucho si los indicadores inteligentes implementan la semántica de vida deseada: realmente no crees que es imposible que mi esposa muera antes que yo (o que mi muerte deba desencadenar la suya), ¿verdad? –

+0

@JamesKanze entonces, ¿por qué sería un problema? ¿El uso de punteros inteligentes le impediría eliminar el objeto esposa de antemano, o eliminarlo después de que la persona haya muerto? –

+0

depende del puntero inteligente, pero si elimina algo administrado por cualquiera de los punteros inteligentes estándar, se encuentra en un terreno de comportamiento indefinido. Si usa 'shared_ptr', especialmente, la vida útil del objeto está fuera de sus manos. –

1

punteros inteligentes pueden ayudarle a

using boost::shared_ptr; // or std::shared_ptr, or std::tr1::shared_ptr or something like this 
class Person { 

private: 
    shared_ptr<Wife> current_wife; 
    //..... 
}; 

Person::SetCurrentWife (shared_ptr<Wife> new_wife) { 

    current_wife = new_wife; 
} 

Y ahora no deberían eliminar cualquier mujer en absoluto.

shared_ptr<Person> some_person (new Person); 
... 
shared_ptr<Wife> wife (new Wife); 
some_person->SetCurrentWife(wife); 
+3

Esto suena como una receta para el desastre. Solo existen unos pocos casos en los que funciona 'shared_ptr', y sospecho que este no es uno de ellos. Por dos razones: primero, es probable que 'Esposa' también sepa de quién es esposa, por lo que tienes un ciclo (y necesitas un ciclo, ya que si algo le sucede a 'Esposa', se debe informar al cónyuge actual). Y en segundo lugar, la vida de 'Wife' ciertamente no depende de la vida de la esposa --- si' Wife' muere, no se la debe mantener viva solo porque la esposa le mantenga un puntero. –

+0

@JamesKanze es por eso que 'boost :: weak_ptr' supongo. Permite ciclos de corte y notificación segura de objetos muertos. – cheind

+0

@ChristophHeindl Entonces, ¿qué indicadores deberían ser débiles y cuáles no? 'boost :: weak_ptr' es un truco, y generalmente no se puede usar. –

7

Depende de lo que estés tratando de hacer. En primer lugar, como Kerrek SB tiene comentó, no desea utilizar punteros si la semántica del valor puede ser aplicada: si Wife es copiable y asignable, no hay casi ninguna razón para asignarlo dinámicamente. En este caso, sin embargo, supongo que Wife deriva de Person (aunque quizás un decorador de Person sería más apropiado, ya que el hecho de que un determinado Person ISA Wife puede cambiar con el tiempo), que podría ser incluso tipos derivados desde Wife (y que Person::current_wife pueden querer tener uno de estos), y que, de hecho, Wife tiene identidad; no desea copias de la misma esposa en todo el lugar.

Si este es el caso, entonces realmente tiene que definir un protocolo para las interacciones de otras clases con Wife.Normalmente, el tiempo de vida de Wife no dependerá de la Person que lo tiene (aunque si se trata de un decorador , que podría), por lo que debe Person acaba de celebrar un puntero a ella, como que has hecho. Lo más probable, el objeto Wife tendrá varias funciones el que el control — implícita o explícitamente — su vida útil: que pueda tener algo como:

void Wife::die() 
{ 
    // ... 
    delete this; 
} 

por ejemplo. En ese caso, sin embargo, quien esté casado con Wife tendrá tiene que ser informado, de modo que current_wife no apunta a un cónyuge muerto . Normalmente, se puede usar alguna variante del patrón de observador para esto. (Observe que tiene exactamente el mismo problema en Java;.. No lo hace quieren Person::current_wife para apuntar a un muerto Wife Así que usted todavía necesita una función Wife::die(), y el patrón de observador para notificar al cónyuge )

en casos como este (que en mi experiencia representan la gran mayoría de objetos asignados dinámicamente en C++), sobre la única diferencia entre C++ y Java es que C++ tiene una sintaxis especial para llamar la “ destructor ”; en Java, utiliza la función usual llamada sintaxis, y puede darle a la función el nombre que desee (aunque dispose parece ampliamente utilizado). La sintaxis especial permite al compilador generar código adicional para liberar la memoria, pero todas las demás actividades asociadas con el final de la duración del objeto todavía tienen que programarse (en el destructor, en C++ — aunque en este caso, es puede tener sentido poner algunos de ellos directamente en la función Wife::die ).

Cuestiones relacionadas