Pregunta

Supongamos que tengo una estructura " " 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 adelante, en alguna otra parte del código, paso una instancia de s por valor a alguna función. ¿Estoy haciendo una copia superficial aquí? Supongamos que no implementé ningún constructor de copia u operador de asignación ni nada para s ... solo el constructor predeterminado.

¿Fue útil?

Solución

Para hacer un seguimiento de lo que dijo [[don.neufeld.myopenid.com], no es solo una copia superficial, sino que también es (elige) 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.

Siempre implementa un constructor y operador de copia = en clases que usan punteros de memoria sin procesar.

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;
};

No hace falta decir que este es un gran dolor y hay algunas sutilezas para hacerlo bien. Ni siquiera estoy completamente seguro de haberlo hecho aquí y lo he hecho varias veces. No olvide que tiene que copiar todos los miembros; si agrega algunos nuevos más adelante, ¡no se olvide de agregarlos también!

Haga que el constructor y el operador de copia = privado en su clase. Este es el " bloqueo de la puerta " solución. Es simple y eficaz, pero a veces sobreprotectora.

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

Nunca use punteros en bruto. Esto es simple y efectivo. Hay muchas opciones aquí:

  • Utilice clases de cadena en lugar de punteros de caracteres brutos
  • Use std :: auto_ptr, boost :: 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)
  {
  }
};

Otros consejos

Sí, eso 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.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top