unidad tamaño significado saber que formatear elegir como asignacion c++ c++11

c++ - tamaño - Constructor de movimiento predeterminado vs. Constructor de copia predeterminado vs. Operador de asignación predeterminado



tamaño de la unidad de asignacion ssd (3)

Creo que la compatibilidad con versiones anteriores juega un papel importante aquí. Si el usuario define cualquiera de las funciones de "Regla de tres" (ctor de copia, op de asignación de copia, dtor), se puede asumir que la clase realiza alguna administración de recursos internos. La definición implícita de un constructor de movimiento podría hacer que la clase no sea válida de repente cuando se compile en C ++ 11.

Considera este ejemplo:

class Res { int *data; public: Res() : data(new int) {} Res(const Res &arg) : data(new int(*arg.data)) {} ~Res() { delete data; } };

Ahora, si se generara un constructor de movimiento predeterminado para esta clase, su invocación llevaría a una doble eliminación de data .

En cuanto al operador de asignación de movimientos que evita las definiciones predeterminadas del constructor de movimientos: si el operador de la asignación de movimientos hace algo distinto al predeterminado, probablemente sea incorrecto utilizar el constructor de movimientos predeterminado. Eso es solo la "Regla de tres" / "Regla de cinco" vigente.

¿Por qué el compilador de C ++ tiene más restricciones en los constructores de movimiento generados automáticamente que en el constructor de copia u operador de asignación generados automáticamente?

Los constructores de movimientos generados automáticamente se generan solo si el usuario no ha definido nada (es decir, constructor, copia, asignación, destructor ...)

El constructor de copia o el operador de asignación se generan solo si el usuario no ha definido respectivamente el constructor de copia o el operador de asignación.

Me pregunto por qué la diferencia.


Cuando se creó C ++, se decidió que el constructor predeterminado, el constructor de copia, el operador de asignación y el destructor se generarían automáticamente (a menos que se proporcionara). Por qué ? Debido a que los compiladores de C ++ deberían poder compilar (la mayoría) el código C con semántica idéntica, y así es como funciona la struct en C.

Sin embargo, más tarde se notó que cada vez que un usuario escribe un destructor personalizado, es probable que ella también necesite escribir un constructor de copia / operador de asignación personalizado; Esto se conoce como la Regla de los Tres Grandes . En retrospectiva, podemos ver que se podría haber especificado que el constructor de copia / operador de asignación / destructor generado solo se generaría si ninguno de los 3 fuera proporcionado por el usuario, y hubiera ayudado a detectar muchos errores. .. y aún conserva compatibilidad hacia atrás con C.

Por lo tanto, cuando llegó C ++ 11, se decidió que esta vez las cosas se harían bien: el nuevo constructor de movimientos y el operador de asignación de movimientos solo se generarían automáticamente si estaba claro que el usuario no estaba haciendo nada " especial "con la clase. Cualquier cosa "especial" se define como redefinir el comportamiento de movimiento / copia / destrucción.

Para ayudar con el caso, las personas estarían haciendo algo especial, pero todavía querían métodos especiales "generados automáticamente", también se agregó la capa de azúcar por = default .

Desafortunadamente, por razones de compatibilidad con versiones anteriores, el comité de C ++ no pudo retroceder en el tiempo y cambiar las reglas de generación automática para la copia; Ojalá lo hubieran desaprobado para allanar el camino para la próxima versión del Estándar, pero dudo que lo hagan. sin embargo, está en desuso (consulte §12.8 / 7 para el constructor de copias, por ejemplo, cortesía de @Nevin).


Que yo sepa, esto es debido a la compatibilidad descendente. Considere las clases escritas en C ++ (antes de C ++ 11) y qué pasaría si C ++ 11 comenzara a generar automáticamente movimientos en paralelo a los copiadores existentes o, en general, a cualquier otro ctor. Rompería fácilmente el código existente, al pasar el copy-ctor que escribió el autor de esa clase. Por lo tanto, las reglas para generar un move-ctor fueron diseñadas para aplicarse solo a casos "seguros".

Aquí está el artículo de Dave Abrahams sobre por qué el movimiento implícito debe irse , lo que finalmente llevó a las reglas actuales de C ++ 11.

Y este es un ejemplo de cómo fallaría:

// NOTE: This example assumes an implicitly generated move-ctor class X { private: std::vector<int> v; public: // invariant: v.size() == 5 X() : v(5) {} ~X() { std::cout << v[0] << std::endl; } }; int main() { std::vector<X> y; // and here is where it would fail: // X() is an rvalue: copied in C++03, moved in C++0x // the classes'' invariant breaks and the dtor will illegally access v[0]. y.push_back(X()); }