2008-10-19 10 views
5

Digamos que tengo una struct "s" con una variable de miembro de puntero int "i". Asigno memoria en el montón para i en el constructor predeterminado de s. Más tarde, en alguna otra parte del código, paso una instancia de s por valor a alguna función. ¿Estoy haciendo una copia superficial aquí? Supongo que no implementé ningún constructor de copias ni operadores de asignación ni nada por s ... solo el constructor predeterminado.Pregunta sobre copia superficial en C++

Respuesta

8

Para hacer un seguimiento de lo que @ [don.neufeld.myopenid.com] dijo, no es solo una copia superficial, sino que es (elija) una pérdida de memoria o un puntero colgante.

// memory leak (note that the pointer is never deleted) 
class A 
{ 
    B *_b; 
    public: 
    A() 
    : _b(new B) 
    { 
    } 
}; 

// dangling ptr (who deletes the instance?) 
class A 
{ 
    B *_b; 
    public: 
    A() 
    ... (same as above) 

    ~A() 
    { 
    delete _b; 
    } 
}; 

Para resolver esto, hay varios métodos.

Implemente siempre un constructor de copias y operator = en clases que usan punteros de memoria sin formato.

class A 
{ 
    B *_b; 
    public: 
    A() 
    ... (same as above) 

    ~A() 
    ... 

    A(const A &rhs) 
    : _b(new B(rhs._b)) 
    { 
    } 

    A &operator=(const A &rhs) 
    { 
    B *b=new B(rhs._b); 
    delete _b; 
    _b=b; 
    return *this; 
}; 

Huelga decir que esto es un gran dolor y hay un buen número de sutilezas para hacerlo bien. Ni siquiera estoy totalmente seguro de haberlo hecho aquí y lo he hecho algunas veces. No olvide que debe copiar todos los miembros; si agrega algunos nuevos más adelante, ¡no olvide agregarlos también!

Realice el constructor de copia y el operador = privado en su clase. Esta es la solución de "bloquear la puerta". Es simple y efectivo, pero a veces es sobreprotector.

class A : public boost::noncopyable 
{ 
    ... 
}; 

Nunca use punteros primas. Esto es simple y efectivo. Hay un montón de opciones aquí:

  • clases de uso de cadenas en lugar de punteros de char primas
  • uso std :: auto_ptr, impulsar :: shared_ptr, boost :: scoped_ptr etc

Ejemplo:

// uses shared_ptr - note that you don't need a copy constructor or op= - 
// shared_ptr uses reference counting so the _b instance is shared and only 
// deleted when the last reference is gone - admire the simplicity! 
// it is almost exactly the same as the "memory leak" version, but there is no leak 
class A 
{ 
    boost::shared_ptr<B> _b; 
    public: 
    A() 
    : _b(new B) 
    { 
    } 
}; 
+0

Su operador de asignación no es una excepción segura. Consulte la pregunta reciente sobre seguridad de copia y excepciones: http://stackoverflow.com/questions/214891/checklist-for-writing-copy-constuctor-and-assignment-operator-in-c#214966 –

+0

Doh, vale, lo arreglé . Ya ves lo que quiero decir sobre que es un dolor y es difícil de conseguir, entonces eh –

+0

La mejor manera de hacer que el constructor de copia y el operador = privado sea heredar de boost :: noncopyable. Debe hacer eso para cada clase a menos que sepa con certeza que se podrá copiar. – CesarB

5

Sí, es una copia superficial. Ahora tiene dos copias de s (una en la persona que llama, una en la pila como parámetro), cada una de las cuales contiene un puntero al mismo bloque de memoria.

2

Usted tendrá dos copias de la s estructura, cada uno de los cuales tendrá su propio puntero i, pero ambos i punteros tendrá el mismo valor que apunta a la misma dirección en la memoria - así que sí, será una copia superficial .

Cuestiones relacionadas