evitar la copia accidental de objetos en C++
copying (5)
Estás en el camino correcto. Si no desea utilizar boost, puede hacer lo siguiente: Hacer que el constructor de copia y el operador de asignación de copia sean privados y no implementarlos. Por lo tanto, obtendrá un error del compilador si intenta copiar una instancia.
En el estándar de codificación de nuestra compañía, se nos ha dicho que "seamos conscientes de las formas en que se puede evitar la copia (accidental)".
No estoy realmente seguro de lo que esto significa, pero supongo que significan que deberíamos evitar que las clases se copien si no es necesario.
Lo que puedo pensar es lo siguiente:
- Hacer que el constructor de copia de una clase sea privado.
- Haga que el operador de asignación (operator =) de una clase sea privado.
- Haga que el constructor de una clase sea explícito (para evitar que las clases se creen usando variables incorrectas).
- Para todas las clases que llevan a cabo la asignación de memoria y donde se requiere la copia, asegúrese de que el constructor de la copia y el operador de la asignación realicen la copia profunda en lugar de la copia superficial.
¿Estoy en el camino correcto? ¿Hay algo que pueda haber perdido?
Sí, hacer que el operador de asignación y el constructor de copias sean privados le impedirá crear cualquier copia de un objeto usando métodos estándar (pero si realmente necesita una copia de un objeto, puede implementar, por ejemplo, el método Copy (), que realizará una copia en profundidad) .
Echa un vistazo a boost::noncopyable .
Actualización (con respecto a Tal Pressman):
... debe tener en cuenta estas cosas y vigilar que no copie accidentalmente los objetos que no debería.
Bueno, supongo, que cualquier copia accidental se realizará utilizando un operador de asignación o un constructor de copias. Por lo tanto, hacerlos privados tiene sentido: si la copia del objeto es una operación costosa, entonces la copia debe ser explícita: otro desarrollador puede llamar involuntariamente indirectamente a copy op y el compilador le informará que esto está prohibido.
Si está usando boost, la forma más fácil de evitar que una clase se copie es derivar su clase de no noncopyable :
#include <boost/noncopyable.hpp>
class Foo : private boost::noncopyable
{
}
Hace que su intención sea más clara que hacer que el constructor de copias y el operador de operaciones sean privados, y tiene el mismo resultado.
Si su estándar de codificación dice "ser consciente de las formas en que se puede evitar la copia (accidental)", supongo que no solo se trata de prevenir las copias desde dentro de las clases en sí, sino de las implicaciones de rendimiento de las copias innecesarias / accidentales cuando usando las clases.
Una de las principales causas del rendimiento innecesariamente perdido en el código de personas nuevas en C ++ es la copia innecesaria, generalmente a través de temporarios. Los compiladores se están volviendo cada vez mejores a la hora de decidir cuándo no son necesarios los temporales (consulte "¿Desea velocidad? Pase por valor" , gracias al comentario de Konrad), pero lo mejor que puede hacer es aprender a conocer el funcionamiento interno de las copias y los temporales. en C ++ (entre otros). Para mí, leer Efficient C ++ realmente me hizo comenzar.
Su lista se ve muy bien desde el punto de vista de evitar errores, por ejemplo, eliminar la misma área de memoria más de una vez debido a los punteros compartidos de la copia implícita de objetos.
Espero que esto también sea relevante; a partir de la frase "tenga en cuenta las formas en que se puede evitar la copia (accidental)", podría interpretar que significa "ser consciente de una copia innecesaria no intencional". Esto significaría circunstancias que podrían afectar el rendimiento. En un ejemplo muy simple, sus convenciones de codificación podrían significar que debería preferir:
std::string text1( "some text" );
terminado:
std::string text1 = "some text";
El segundo caso daría lugar a que se creara una cadena temporal para contener "algún texto" antes de invocar al operador de asignación (una forma de copia) para rellenar el texto1 con "algo de texto". Obviamente, este es un ejemplo trivial y una buena práctica diría que debe usar la inicialización del constructor (primer ejemplo) siempre que sea posible.