Skip to content
Menu
CDhistory
CDhistory

Constructores de movimiento

Posted on mayo 26, 2021 by admin

Un constructor de movimiento de la clase T es un constructor sin plantilla cuyo primer parámetro es T&&, const T&&, volatile T&&, o const volatile T&&, y o bien no hay otros parámetros, o el resto de los parámetros tienen todos valores por defecto.

  • Contenido
  • Sintaxis
  • Explicación
  • Constructor de movimiento declarado implícitamente
  • Constructor de movimiento declarado implícitamente eliminado
  • Constructor de movimiento trivial
  • Constructor move elegible
  • Constructor de movimiento definido implícitamente
  • Notas
  • Ejemplo
  • Informes de defectos
  • Véase también

Contenido

  • 1 Sintaxis
  • 2 Explicación
  • 3 Constructor de movimiento declarado implícitamente
  • 4 Constructor de movimiento declarado implícitamente eliminado
  • 5 Constructor de movimiento trivial
  • 6 Constructor de movimiento elegible
  • 7 Constructor de movimiento definido implícitamente
  • .constructor de movimientos definido implícitamente

  • 8 Notas
  • 9 Ejemplo
  • 10 Informes de defectos
  • 11 Véase también

Sintaxis

nombre_clase ( nombre_clase && ) (1) (desde C++11)
nombre_clase ( nombre_clase && ) = por defecto; (2) (desde C++11)
class_name ( class_name && ) = delete; (3) (desde C++11)

Donde class_name debe nombrar la clase actual (o la instanciación actual de una plantilla de clase), o, cuando se declara en el ámbito del espacio de nombres o en una declaración de amigo, debe ser un nombre de clase cualificado.

Explicación

1) Declaración típica de un constructor de movimiento.
2) Forzar un constructor de movimiento a ser generado por el compilador.
3) Evitar el constructor de movimiento implícito.

El constructor move es típicamente llamado cuando un objeto es inicializado (por inicialización directa o por copia-inicialización) desde rvalue (xvalue o prvalue) (hasta C++17)xvalue (desde C++17) del mismo tipo, incluyendo

  • inicialización: T a = std::move(b); o T a(std::move(b));, donde b es del tipo T;
  • paso de argumentos de funciones: f(std::move(a));, donde a es de tipo T y f es void f(T t);
  • función return: return a; dentro de una función como T f(), donde a es de tipo T que tiene un constructor move.

Cuando el inicializador es un prvalue, la llamada al constructor move a menudo se optimiza (hasta C++17)nunca se hace (desde C++17), ver copy elision.

Los constructores move típicamente «roban» los recursos que tiene el argumento (e.g. punteros a objetos asignados dinámicamente, descriptores de archivo, sockets TCP, flujos de E/S, hilos en ejecución, etc.) en lugar de hacer copias de ellos, y dejar el argumento en algún estado válido pero indeterminado. Por ejemplo, pasar de un std::string o de un std::vector puede hacer que el argumento quede vacío. Sin embargo, no se debe confiar en este comportamiento. Para algunos tipos, como std::unique_ptr, el estado «moved-from» está completamente especificado.

Constructor de movimiento declarado implícitamente

Si no se proporcionan constructores de movimiento definidos por el usuario para un tipo de clase (struct, class, o union), y todo lo siguiente es verdadero:

  • no hay constructores de copia declarados por el usuario;
  • no hay operadores de asignación de copia declarados por el usuario;
  • no hay operadores de asignación de movimiento declarados por el usuario;
  • no hay destructor declarado por el usuario.

entonces el compilador declarará un constructor de movimiento como un miembro no explícito inline public de su clase con la firma T::T(T&&).

Una clase puede tener múltiples constructores de movimiento, por ejemplo, tanto T::T(const T&&) como T::T(T&&). Si algunos constructores de movimiento definidos por el usuario están presentes, el usuario todavía puede forzar la generación del constructor de movimiento declarado implícitamente con la palabra clave default.

El constructor de movimiento declarado implícitamente (o por defecto en su primera declaración) tiene una especificación de excepciones como se describe en la especificación de excepciones dinámicas (hasta C++17)especificación de excepciones (desde C++17)

Constructor de movimiento declarado implícitamente eliminado

El constructor de movimiento declarado implícitamente o por defecto para la clase T se define como eliminado si cualquiera de los siguientes es verdadero:

  • T tiene miembros de datos no estáticos que no se pueden mover (tienen constructores de movimiento borrados, inaccesibles o ambiguos);
  • T tiene una clase base directa o virtual que no se puede mover (tiene constructores de movimiento borrados, inaccesibles o ambiguos);
  • T tiene clase base directa o virtual con un destructor borrado o inaccesible;
  • T es una clase tipo unión y tiene un miembro variante con constructor de movimiento no trivial.

Un constructor de movimiento por defecto que es borrado es ignorado por la resolución de sobrecarga (de lo contrario impediría la copia-inicialización de rvalue).

Constructor de movimiento trivial

El constructor de movimiento para la clase T es trivial si todo lo siguiente es cierto:

  • no es proporcionado por el usuario (es decir, está definido implícitamente o por defecto);
  • T no tiene funciones miembro virtuales;
  • T no tiene clases base virtuales;
  • el constructor de movimiento seleccionado para cada base directa de T es trivial;
  • el constructor de movimiento seleccionado para cada tipo de clase no estática (o matriz de tipo de clase) miembro de T es trivial.

Un constructor de movimiento trivial es un constructor que realiza la misma acción que el constructor de copia trivial, es decir, hace una copia de la representación del objeto como si fuera por std::memmove. Todos los tipos de datos compatibles con el lenguaje C (tipos POD) son trivialmente movibles.

Constructor move elegible

Un constructor move es elegible si no se borra.

(hasta C++20)

Un constructor de movimiento es elegible si

  • no se elimina, y
  • sus restricciones asociadas, si las hay, se satisfacen, y
  • ningún constructor de movimiento con el mismo tipo de primer parámetro está más restringido que él.
(desde C++20)

La trivialidad de los constructores de movimiento elegibles determina si la clase es un tipo de vida implícita, y si la clase es un tipo trivialmente copiable.

Constructor de movimiento definido implícitamente

Si el constructor de movimiento declarado implícitamente no es ni borrado ni trivial, es definido (es decir, se genera y compila un cuerpo de función) por el compilador si se utiliza odr o se necesita para la evaluación constante. Para los tipos de unión, el constructor de movimiento definido implícitamente copia la representación del objeto (como por std::memmove). Para los tipos de clase que no son de unión (class y struct), el constructor move realiza un movimiento completo de las bases del objeto y de los miembros no estáticos, en su orden de inicialización, utilizando la inicialización directa con un argumento xvalue. Si esto satisface los requisitos de un constructor constexpr, el constructor move generado es constexpr.

Notas

Para hacer posible la garantía de excepción fuerte, los constructores move definidos por el usuario no deberían lanzar excepciones. Por ejemplo, std::vector se basa en std::move_if_noexcept para elegir entre mover y copiar cuando los elementos necesitan ser reubicados.

Si se proporcionan los constructores copy y move y no hay otros constructores viables, la resolución de sobrecarga selecciona el constructor move si el argumento es un rvalue del mismo tipo (un xvalue como el resultado de std::move o un prvalue como un temporal sin nombre (hasta C++17)), y selecciona el constructor copy si el argumento es un lvalue (objeto con nombre o una función/operador que devuelve una referencia lvalue). Si sólo se proporciona el constructor de copia, todas las categorías de argumentos lo seleccionan (siempre que tome una referencia a const, ya que los rvalues pueden enlazarse a referencias const), lo que hace que la copia sea el fallback para mover, cuando mover no está disponible.

Un constructor se llama ‘move constructor’ cuando toma una referencia rvalue como parámetro. No está obligado a mover nada, la clase no está obligada a tener un recurso para ser movido y un ‘move constructor’ puede no ser capaz de mover un recurso como en el caso permitido (pero tal vez no sensible) donde el parámetro es una referencia rvalue const (const T&&).

Ejemplo

Ejecuta este código
#include <string>#include <iostream>#include <iomanip>#include <utility> struct A{ std::string s; int k; A() : s("test"), k(-1) { } A(const A& o) : s(o.s), k(o.k) { std::cout << "move failed!\n"; } A(A&& o) noexcept : s(std::move(o.s)), // explicit move of a member of class type k(std::exchange(o.k, 0)) // explicit move of a member of non-class type { }}; A f(A a){ return a;} struct B : A{ std::string s2; int n; // implicit move constructor B::(B&&) // calls A's move constructor // calls s2's move constructor // and makes a bitwise copy of n}; struct C : B{ ~C() { } // destructor prevents implicit move constructor C::(C&&)}; struct D : B{ D() { } ~D() { } // destructor would prevent implicit move constructor D::(D&&) D(D&&) = default; // forces a move constructor anyway}; int main(){ std::cout << "Trying to move A\n"; A a1 = f(A()); // return by value move-constructs the target from the function parameter std::cout << "Before move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n'; A a2 = std::move(a1); // move-constructs from xvalue std::cout << "After move, a1.s = " << std::quoted(a1.s) << " a1.k = " << a1.k << '\n'; std::cout << "Trying to move B\n"; B b1; std::cout << "Before move, b1.s = " << std::quoted(b1.s) << "\n"; B b2 = std::move(b1); // calls implicit move constructor std::cout << "After move, b1.s = " << std::quoted(b1.s) << "\n"; std::cout << "Trying to move C\n"; C c1; C c2 = std::move(c1); // calls copy constructor std::cout << "Trying to move D\n"; D d1; D d2 = std::move(d1);}

Salida:

Trying to move ABefore move, a1.s = "test" a1.k = -1After move, a1.s = "" a1.k = 0Trying to move BBefore move, b1.s = "test"After move, b1.s = ""Trying to move Cmove failed!Trying to move D

Informes de defectos

Los siguientes informes de defectos que cambian el comportamiento se aplicaron retroactivamente a las normas C++ publicadas anteriormente.

DR Aplicado a Comportamiento como se publicó Comportamiento correcto
CWG 1402 C++11 se eliminó un constructor de movimiento por defecto que
llamaría a un constructor de copia no trivial;
un constructor de movimiento por defecto que se elimina
aún participaba en la resolución de sobrecarga
permite llamar a dicho constructor de copia;
hecho ignorado en la resolución de sobrecarga
CWG 2094 C++11 un subobjeto volátil hecho de un constructor de movimiento predeterminado
notrivial (CWG496)
la trivialidad no se ve afectada

Véase también

  • constructor de conversión
  • asignación de copia
  • constructor de copia
  • elisión de copia
  • constructor por defecto
  • destructor
  • explícito
  • inicialización
    • inicialización agregada
    • inicialización constante
    • inicialización de copia
    • inicialización por defecto
    • inicialización directa
    • inicializador de lista
    • inicialización de lista
    • inicialización de referencia
    • inicialización de valor
    • inicialización cero
  • asignación de movimiento
  • nuevo

Deja una respuesta Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Entradas recientes

  • Acela está de vuelta: NYC o Boston por 99 dólares
  • Entrada OMIM – # 608363 – SÍNDROME DE DUPLICACIÓN DEL CROMOSOMA 22q11.2
  • Los padres de Kate Albrecht – Conoce más sobre su padre Chris Albrecht y su madre Annie Albrecht
  • Temple Fork Outfitters
  • Burr (novela)

Archivos

  • febrero 2022
  • enero 2022
  • diciembre 2021
  • noviembre 2021
  • octubre 2021
  • septiembre 2021
  • agosto 2021
  • julio 2021
  • junio 2021
  • mayo 2021
  • abril 2021
  • DeutschDeutsch
  • NederlandsNederlands
  • SvenskaSvenska
  • DanskDansk
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • RomânăRomână
  • PolskiPolski
  • ČeštinaČeština
  • MagyarMagyar
  • SuomiSuomi
  • 日本語日本語
©2022 CDhistory | Powered by WordPress & Superb Themes