2011-04-18 13 views
20

A veces es necesario prohibir un constructor de copia en una clase de C++ para que la clase se convierta en "no copiable". Por supuesto, operator= debe prohibirse al mismo tiempo.¿Cuál es la forma más confiable de prohibir un constructor de copia en C++?

Hasta ahora he visto dos formas de hacerlo. Vía 1 es declarar el método privado y darle ninguna aplicación:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&); //not implemented anywhere 
    void operator=(const Class&); //not implemented anywhere 
}; 

modo 2 es declarar el método privado y darle aplicación "vacío":

class Class { 
//useful stuff, then 
private: 
    Class(const Class&) {} 
    void operator=(const Class&) {} 
}; 

OMI el primero es mejor - incluso si hay alguna razón inesperada que conduzca al llamado al constructor de copia desde la misma función de miembro de la clase, habrá un error de enlazador más adelante. En el segundo caso, este escenario no se detectará hasta el tiempo de ejecución.

¿Hay algún inconveniente serio en el primer método? ¿Cuál es una mejor manera si hay alguna y por qué?

+4

http://www.boost.org/doc/libs/1_46_1/boost/noncopyable.hpp – dgnorton

Respuesta

16

El primer método es cómo Boost lo resuelve (source code), hasta donde yo sé, no hay inconvenientes. De hecho, los errores del enlazador son la gran ventaja de ese método. Desea que los errores estén en tiempo de enlace, no cuando su cliente está ejecutando su código y de repente se bloquea.

En caso de que esté utilizando Boost, puede ahorrarse algunos tipeos. Esto hace lo mismo que el primer ejemplo:

#include <boost/utility.hpp> 

class Class : boost::noncopyable { 
// Stuff here 
} 
+7

Si bien podría ser "cómo Boost lo resuelve", todavía hay una diferencia significativa entre resolverlo de esa manera en una clase base y hacerlo usted mismo en su propia clase, ya que el enfoque de clase base es mucho más autodocumentado, evitando que alguien Añadiéndolo descuidadamente en la clase más tarde, pensando que no fue implementado por error. –

+0

Eso seguiría siendo un buen escenario, ya que le permite atrapar a alguien antes de que haga un daño real. Por supuesto, no se puede esperar que los juniors sepan esto, pero de todos modos no deberían hacer esos cambios sin revisión. – MSalters

+0

@Tony: prefiero la alternativa de impulso también (u otra clase personalizada cuando no se puede usar el impulso). Es más fácil de entender, mucho más legible, y los mensajes de error son un poco mejores. –

25

El primero de ellos es mejor

Aún mejor es C++0x 'delete' keyword:

class Class { 
// useful stuff, then 
public: 
    Class(const Class&) = delete; 
    void operator=(const Class&) = delete; 
}; 
+6

@sehe: con 'delete' no hay motivo para hacerlo privado. De hecho, parece que hacerlo aparecer en la interfaz pública parece ser mejor para el usuario. –

+0

buen punto. actualizando – sehe

+0

@Matthieu El uso de 'delete' en este contexto es C++ 11; si tiene que apuntar a compiladores más antiguos, e incluso a muchos más recientes, no puede usarlo. –

7

Siempre se puede heredar de boost::noncopyable.

De lo contrario, nunca he visto una razón que el número 2 sea mejor que el número 1, ya que le permitirá copiar un objeto dentro de los métodos friend o class aunque no creará una copia verdadera del objeto .

2

No hay inconveniente en su primera aproximación, que ha estado utilizando para hacer que la clase "no copiable" ..

3

Como otras respuestas sugieren otra cosa , y realmente no intenta responder a la pregunta, así que aquí está mi intento:

Entonces, ¿qué enfoque es mejor? Depende de cómo defina prohibir copia?

Si desea evitar que otros (solo las clases y funciones que no son de amigos) copien mientras permite que amigos y funciones de miembros copien, entonces el segundo enfoque es el camino a seguir.

Si desea evitar que todos (amigos, no amigos, funciones de miembros) copien, entonces el primer enfoque es la única solución correcta.

Tenga en cuenta que el segundo enfoque no impide que amigos y funciones miembro copien (es decir, que no llamen a las funciones de copia).

1. Si no las define correctamente en el segundo caso, entonces la copia no funcionaría, como se esperaba, pero eso es completamente diferente. Pero el punto es que el segundo caso no impide llamar a las funciones de copia. El compilador no generaría ningún mensaje de error.

1

Personalmente, creo que ha respondido a su propia pregunta y debería usar el primer enfoque.

Si no quiere que se pueda copiar en absoluto, como dijo, arrojará un error de enlazador. Sin embargo, si utilizas el segundo método y terminas utilizando el constructor de copias por accidente, SE COMPARARÁ y se ejecutará; y no tendrá absolutamente ninguna indicación de dónde salió la inconsistencia hasta que abra un depurador. O como dijo, si puede usar un compilador moderno, use la notación '= delete' de C++ 11.

Cuestiones relacionadas