Namespaces
Variants

Copy assignment operator

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Un operador de asignación de copia es una función miembro no estática no plantilla con el nombre operator = que puede ser llamado con un argumento del mismo tipo de clase y copia el contenido del argumento sin modificar el argumento.

Contenidos

Sintaxis

Para la sintaxis formal del operador de asignación de copia, consulte declaración de función . La lista de sintaxis a continuación solo demuestra un subconjunto de todas las sintaxis válidas del operador de asignación de copia.

tipo-de-retorno operator=( lista-de-parámetros  ); (1)
tipo-de-retorno operator=( lista-de-parámetros  ) cuerpo-de-función (2)
tipo-de-retorno operator=( lista-de-parámetros-sin-valor-predeterminado  ) = default; (3) (desde C++11)
tipo-de-retorno operator=( lista-de-parámetros  ) = delete; (4) (desde C++11)
tipo-de-retorno nombre-de-clase  :: operator=( lista-de-parámetros  ) cuerpo-de-función (5)
tipo-de-retorno nombre-de-clase  :: operator=( lista-de-parámetros-sin-valor-predeterminado  ) = default; (6) (desde C++11)
class-name - la clase cuyo operador de asignación de copia se está declarando, el tipo de clase se da como T en las descripciones siguientes
parameter-list - una lista de parámetros de solo un parámetro, que es de tipo T , T& , const T & , volatile T & o const volatile T &
parameter-list-no-default - una lista de parámetros de solo un parámetro, que es de tipo T , T& , const T & , volatile T & o const volatile T & y no tiene un argumento predeterminado
function-body - el cuerpo de función del operador de asignación de copia
return-type - cualquier tipo, pero T& es preferido para permitir encadenamiento de asignaciones

Explicación

1) Declaración de un operador de asignación de copia dentro de la definición de clase.
2-4) Definición de un operador de asignación de copia dentro de la definición de clase.
3) El operador de asignación de copia está explícitamente predeterminado.
4) El operador de asignación de copia está eliminado.
5,6) Definición de un operador de asignación de copia fuera de la definición de clase (la clase debe contener una declaración (1) ).
6) El operador de asignación de copia está explícitamente predeterminado.
struct X
{
    X& operator=(X& other);     // operador de asignación de copia
    X operator=(X other);       // se permite paso por valor
//  X operator=(const X other); // Error: tipo de parámetro incorrecto
};
union Y
{
    // los operadores de asignación de copia pueden tener sintaxis no listadas arriba,
    // siempre que sigan la sintaxis general de declaración de funciones
    // y no violen las restricciones enumeradas anteriormente
    auto operator=(Y& other) -> Y&;       // OK: tipo de retorno final
    Y& operator=(this Y& self, Y& other); // OK: parámetro de objeto explícito
//  Y& operator=(Y&, int num = 1);        // Error: tiene otros parámetros que no son de objeto
};

El operador de asignación de copia se llama cuando es seleccionado por la resolución de sobrecarga , por ejemplo, cuando un objeto aparece en el lado izquierdo de una expresión de asignación.

Operador de asignación de copia declarado implícitamente

Si no se proporcionan operadores de asignación de copia definidos por el usuario para un tipo de clase, el compilador siempre declarará uno como un inline public miembro de la clase. Este operador de asignación de copia declarado implícitamente tiene la forma T & T :: operator = ( const T & ) si se cumplen todas las siguientes condiciones:

  • cada base directa B de T tiene un operador de asignación de copia cuyos parámetros son B o const B & o const volatile B & ;
  • cada miembro de datos no estático M de T de tipo clase o array de tipo clase tiene un operador de asignación de copia cuyos parámetros son M o const M & o const volatile M & .

De lo contrario, el operador de asignación de copia declarado implícitamente se declara como T & T :: operator = ( T & ) .

Debido a estas reglas, el operador de asignación de copia declarado implícitamente no puede vincularse a un volatile argumento lvalue.

Una clase puede tener múltiples operadores de asignación de copia, por ejemplo, tanto T & T :: operator = ( T & ) como T & T :: operator = ( T ) . Si existen algunos operadores de asignación de copia definidos por el usuario, el usuario aún puede forzar la generación del operador de asignación de copia declarado implícitamente con la palabra clave default . (desde C++11)

El operador de asignación de copia declarado implícitamente (o predeterminado en su primera declaración) tiene una especificación de excepciones como se describe en especificación de excepciones dinámicas (hasta C++17) especificación noexcept (desde C++17)

Debido a que el operador de asignación de copia siempre se declara para cualquier clase, el operador de asignación de la clase base siempre está oculto. Si una using-declaration se utiliza para traer el operador de asignación desde la clase base, y su tipo de argumento podría ser el mismo que el tipo de argumento del operador de asignación implícito de la clase derivada, la using-declaration también está oculta por la declaración implícita.

Operador de asignación de copia definido implícitamente

Si el operador de asignación de copia declarado implícitamente no está eliminado ni es trivial, se define (es decir, se genera y compila un cuerpo de función) por el compilador si odr-used o needed for constant evaluation (since C++14) . Para tipos union, la asignación de copia definida implícitamente copia la representación del objeto (como mediante std::memmove ). Para tipos class no union, el operador realiza la asignación de copia miembro a miembro de las bases directas y miembros de datos no estáticos del objeto, en su orden de inicialización, usando asignación incorporada para los escalares, asignación de copia miembro a miembro para arrays, y operador de asignación de copia para tipos class (llamado no virtualmente).

El operador de asignación de copia definido implícitamente para una clase T es constexpr si

  • T es un literal type , y
  • el operador de asignación seleccionado para copiar cada subobjeto de clase base directa es una función constexpr, y
  • para cada miembro de datos no estático de T que es de tipo clase (o arreglo del mismo), el operador de asignación seleccionado para copiar ese miembro es una función constexpr.
(desde C++14)
(hasta C++23)

El operador de asignación de copia definido implícitamente para una clase T es constexpr .

(desde C++23)


La generación del operador de asignación de copia definido implícitamente está obsoleta si T tiene un destructor declarado por el usuario o un constructor de copia declarado por el usuario.

(since C++11)

Operador de asignación de copia eliminado

Un operador de asignación de copia declarado implícitamente o explícitamente predeterminado (since C++11) para la clase T está indefinido (until C++11) definido como eliminado (since C++11) si se satisface alguna de las siguientes condiciones:

  • T tiene un miembro de datos no estático de un tipo no-clase calificado como const (o posiblemente un arreglo multidimensional del mismo).
  • T tiene un miembro de datos no estático de tipo referencia.
  • T tiene un subobjeto potencialmente construido de tipo clase M (o posiblemente un arreglo multidimensional del mismo) tal que la resolución de sobrecarga aplicada para encontrar el operador de asignación de copia de M
  • no resulta en un candidato utilizable, o
  • en el caso de que el subobjeto sea un variant member , selecciona una función no trivial.

El operador de asignación de copia declarado implícitamente para la clase T se define como eliminado si T declara un move constructor o un move assignment operator .

(desde C++11)

Operador de asignación de copia trivial

El operador de asignación de copia para la clase T es trivial si se cumplen todas las siguientes condiciones:

  • 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 operador de asignación de copia seleccionado para cada base directa de T es trivial;
  • el operador de asignación de copia seleccionado para cada miembro de tipo clase (o arreglo de tipo clase) no estático de T es trivial.

Un operador de asignación de copia trivial realiza una copia de la representación del objeto como si fuera mediante std::memmove . Todos los tipos de datos compatibles con el lenguaje C (tipos POD) son trivialmente asignables por copia.

Operador de asignación de copia elegible

Un operador de asignación de copia es elegible si es declarado por el usuario o si es declarado implícitamente y definible.

(until C++11)

Un operador de asignación de copia es elegible si no está eliminado.

(since C++11)
(until C++20)

Un operador de asignación de copia es elegible si se satisfacen todas las siguientes condiciones:

(since C++20)

La trivialidad de los operadores de asignación por copia elegibles determina si la clase es un trivially copyable type .

Notas

Si se proporcionan tanto el operador de asignación de copia como el de movimiento, la resolución de sobrecarga selecciona la asignación de movimiento si el argumento es un rvalue (ya sea un prvalue como un temporal sin nombre o un xvalue como el resultado de std::move ), y selecciona la asignación de copia si el argumento es un lvalue (objeto con nombre o una función/operador que devuelve una referencia lvalue). Si solo se proporciona la asignación de copia, todas las categorías de argumentos la seleccionan (siempre que tome su argumento por valor o como referencia a const, ya que los rvalues pueden enlazarse a referencias const), lo que convierte a la asignación de copia en el respaldo para la asignación de movimiento cuando esta no está disponible.

No está especificado si los subobjetos de clase base virtual que son accesibles a través de más de una ruta en el esquema de herencia, son asignados más de una vez por el operador de asignación de copia definido implícitamente (lo mismo aplica para move assignment ).

Consulte sobrecarga del operador de asignación para obtener detalles adicionales sobre el comportamiento esperado de un operador de asignación de copia definido por el usuario.

Ejemplo

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
struct A
{
    int n;
    std::string s1;
    A() = default;
    A(A const&) = default;
    // asignación de copia definida por el usuario (idioma copy-and-swap)
    A& operator=(A other)
    {
        std::cout << "copy assignment of A\n";
        std::swap(n, other.n);
        std::swap(s1, other.s1);
        return *this;
    }
};
struct B : A
{
    std::string s2;
    // asignación de copia definida implícitamente
};
struct C
{
    std::unique_ptr<int[]> data;
    std::size_t size;
    // asignación de copia definida por el usuario (no es el idioma copy-and-swap)
    // nota: copy-and-swap siempre reasignaría recursos
    C& operator=(const C& other)
    {
        if (this != &other) // no es una autoasignación
        {
            if (size != other.size) // el recurso no puede reutilizarse
            {
                data.reset(new int[other.size]);
                size = other.size;
            }
            std::copy(&other.data[0], &other.data[0] + size, &data[0]);
        }
        return *this;
    }
};
int main()
{
    A a1, a2;
    std::cout << "a1 = a2 calls ";
    a1 = a2; // asignación de copia definida por el usuario
    B b1, b2;
    b2.s1 = "foo";
    b2.s2 = "bar";
    std::cout << "b1 = b2 calls ";
    b1 = b2; // asignación de copia definida implícitamente
    std::cout << "b1.s1 = " << b1.s1 << "; b1.s2 = " << b1.s2 << '\n';
}

Salida:

a1 = a2 calls copy assignment of A
b1 = b2 calls copy assignment of A
b1.s1 = foo; b1.s2 = bar

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 1353 C++98 las condiciones donde los operadores de asignación de copia declarados implícitamente
eran indefinidos no consideraban tipos de arreglos multidimensionales
considerar estos tipos
CWG 2094 C++11 un subobjeto volatile hacía que los operadores de asignación de copia predeterminados
fueran no triviales ( CWG issue 496 )
trivialidad no afectada
CWG 2171 C++11 operator = ( X & ) = default era no trivial hecho trivial
CWG 2180 C++11 un operador de asignación de copia predeterminado para la clase T no se definía como eliminado
si T es abstracta y tiene clases base virtuales directas no asignables por copia
el operador se define
como eliminado en este caso
CWG 2595 C++20 un operador de asignación de copia no era elegible si existe
otro operador de asignación de copia que está más
restringido pero no satisface sus restricciones asociadas
puede ser elegible
en este caso

Véase también