Referencia rápida de categorías de valores C ++: Parte 1

imagen

El objetivo de esta referencia rápida es recopilar en un lugar y organizar información sobre categorías de valores en C ++, asignación, paso de parámetros y retorno de funciones. Traté de hacer esta referencia rápida conveniente para comparar y seleccionar rápidamente una de las soluciones posibles, es por eso que hice varias tablas aquí.


Para una introducción al tema, utilice los siguientes enlaces:


C ++ rvalue referencias y semántica de movimiento para principiantes
Valores redefinidos
C ++ se mueve para las personas que no saben o no les importan los valores.
Scott Meyers. Efectivo C ++ moderno. 2015
Comprender la semántica del movimiento y el reenvío perfecto: parte 1
Comprender la semántica del movimiento y el reenvío perfecto: parte 2
Comprender la semántica del movimiento y el reenvío perfecto: parte 3
¿Necesitamos mover y copiar la asignación?


Categorías de valor


imagen


Comenzando con C ++ 11, cualquier expresión puede pertenecer solo a una de tres categorías de valores: lvalue, xvalue o prvalue:


  • xvalue (valor de vencimiento) - expresión, que identifica un objeto no temporal, que se puede mover
  • lvalue (valor izquierdo) - expresión, que identifica un objeto de función no temporal, que no se puede mover
  • prvalue (rvalue puro) - expresión, que inicializa un objeto

imagen


Estas tres categorías se pueden agrupar en tres grupos superpuestos:


  • glvalue (valor generalizado) agrupa lvalue y xvalue. glvalue tiene dirección en la memoria (tiene identidad) y, por lo tanto, generalmente se le puede asignar un valor (si no es constante)
  • rvalue agrupa prvalue y xvalue. rvalue se puede mover (xvalue) o no pertenece a ningún objeto existente (prvalue). rvalue se puede pasar para mover constructores, mover operadores de asignación o mover funciones

Entonces, xvalue tiene una dirección en la memoria y se puede mover.


imagen


Puede ver en la tabla anterior que las variables nombradas de lvalue, lvalue reference y rvalue reference categoties tienen la misma categoría de expresión: lvalue (resaltada en rojo). Por ejemplo, esto significa que cuando se pasa la referencia de valor a una función, se elegirá una sobrecarga de referencia de valor: T&& x=T(); f(x); T&& x=T(); f(x);


Enlaces:
C ++ lvalue rvalue xvalue glvalue prvalue
Categorías de valor en C ++ 17
Categorías de valor


Abreviaturas en este artículo


Abreviaturas de constructores, operadores y destructores:


  • Dc: constructor predeterminado
  • Pc - Constructor parametrizado
  • Cc - Copiar constructor
  • Ca - Asignación de copia (puede reutilizar el almacenamiento asignado, por ejemplo, para std :: string)
  • Mc - Mover constructor
  • Ma - Asignación de movimiento
  • Va: operador de asignación de conversiones
  • D - Destructor

Abreviaturas de categorías de valor:


  • LV - Lvalue: T LV;
  • LR - Referencia de valor de T& LR = LV; : T& LR = LV;
  • XV - Xvalue: move(LV)
  • PRV - Valor puro. Literal o resultado de la llamada a función, cuyo tipo de retorno no es una referencia: T f() { return T(); } T f() { return T(); }
  • FR - Referencia de reenvío: auto&& FR = LV;
  • CLV - const LV. CLR - const LR. CXV - const XV.
  • CPRV - const PRV. CPRV existe solo para clases y matrices. El CPRV sin matriz y sin clase como cont int se convertirá implícitamente a PRV como int , por ejemplo, en el valor de retorno de la función const int f() )
  • RV es XV o PRV
  • CRV es CXV o CPRV

Otras abreviaturas:


  • PF: reenvío perfecto (utilizando la referencia de reenvío con plantilla para pasar el parámetro a la función)

Asignación de categorías de valor


La asignación de categorías de valores puede verse como la base de todas las secciones siguientes. Cuando se asigna explícitamente una categoría a otra sin una conversión explícita de categoría, se produce una conversión implícita: FROM_TYPE x; TO_TYPE y; y = x; FROM_TYPE x; TO_TYPE y; y = x; En la tabla siguiente puede ver qué sucede cuando la expresión de tipo From se asigna a una variable de tipo To:


  • Un signo menos significa que tal asignación no es posible
  • Un signo más significa que tal asignación es posible y no requerirá llamar a operadores o constructores de copiar / mover.
  • En otros casos hay texto, lo que significa qué operadores de copia / movimiento y constructores serán llamados durante dicha asignación.

Las conversiones, que no pueden ocurrir implícitamente desde la categoría de expresión devuelta al tipo de valor de retorno de la función, están marcadas con una fuente roja; consulte la sección "Regresar de una función" a continuación para obtener más detalles.
Las líneas con tipos constantes se resaltan en azul.


imagen


Notas al pie:


1 - Las referencias de auto && Const no son referencias de reenvío, sino referencias de valor constante, por lo que actuarán como
2: un archivo temporal creado para contener un inicializador de referencia persiste hasta el final del alcance de su referencia (consulte la siguiente sección). No funciona para convertir el valor de retorno al tipo de función.
3 - cuando pasa literal, necesita un especificador de tipo a la derecha para auto: auto&& = T{2};


Nota:


  • Las referencias lvalue y rvalue no constantes no pueden aceptar ningún tipo de constante. Pero el tipo sin referencia no const puede aceptar tipos const.
  • La referencia de valor (T&&) puede aceptar xvalue o prvalue (XV o PRV).
  • La referencia de Lvalue (T &) puede aceptar lvalue o lvalue reference (LV o LR)
  • Los tipos sin referencia aceptan cualquier tipo mediante conversión, copia, movimiento o RVO
  • Las referencias de valor constante (const T &, const auto &) y las referencias de reenvío automático (auto &&) aceptan cualquier tipo sin copiar o mover
  • Las referencias de valor constante y no constante (T&&, const T&&) no pueden aceptar valores constantes o no constantes (LV o CLV).
  • LR no puede aceptar referencias de valor constantes o no constantes (XV o PRV o CXV o CPRV). CLR puede aceptarlos.
  • Los tipos con modificadores const no se pueden asignar a ningún tipo sin modificadores const (excepto auto, que puede convertirse en const si const es explícito en el lado derecho).
  • Pasar prvalue (pasar valor de retorno, literal o resultado del constructor) es lo mismo que pasar xvalue, pero evita llamar al constructor de movimiento cuando se asigna un tipo sin referencia
  • Pasar const prvalue (pasar el valor de retorno de la función de tipo const) es lo mismo que pasar const xvalue, pero evita llamar al constructor de copias al asignar un tipo sin referencia
  • Las referencias automáticas pueden convertirse en const, por lo que pueden aceptar variantes const y no const. Además, pueden convertirse en referencias constantes para que persistan temporalmente hasta el final del alcance de la referencia. Pero las referencias automáticas * no pueden volverse constantes si esto no se especifica explícitamente en el lado derecho. Es por eso que no puede asignar rvalue a auto &
  • La referencia constante puede recibir una temporal y hacer que persista hasta el final del alcance de la referencia (la referencia no constante no puede). Esto funciona solo dentro del alcance actual (referencias de funciones locales y argumentos de funciones). Si la referencia es un miembro de una clase, el objeto temporal se destruirá al final del constructor o la función y la referencia continuará apuntando a un objeto destruido, que es un comportamiento indefinido.
  • Auto x = CLV; deducirá auto al tipo no constante.

Ejemplos y pruebas con la impresión de cada constructor y operador llamado
 #include <iostream> #include <iomanip> #include <map> #include <vector> #include <string> using namespace std; template<class C, class T> auto contains(const C& v, const T& x) -> decltype(end(v), true) { return end(v) != std::find(begin(v), end(v), x); } template <class... Types> constexpr inline __attribute__((__always_inline__)) int UNUSED(Types&&...) { return 0; }; map<string, map<string, string>> res; vector<string> froms; vector<string> tos; string from; string to; void report(string st) { if (!from.empty() && !to.empty()) { res[from][to] += st; } cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; T Fprv() { return T(); } const T Fcprv() { return T(); } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } void test_assign(string lto, string lfrom) { from = lfrom; to = lto; res[from][to] = ""; if (!from.empty() && !to.empty()) { if (!contains(froms, from)) froms.push_back(from); if (!contains(tos, to)) tos.push_back(to); } print_col(lto + " = " + lfrom + ": ", 20); } #define TEST_ASSIGN(t, v) { \ test_assign(#t, #v); \ ts = v; \ cout << sa; \ UNUSED(s); \ cout << "-"; \ } void test_conversion() { T l; const T cl; T& lr = l; const T& clr = l; T&& rr = T(); const T&& crr = T(); auto &&fr = T(); TEST_ASSIGN(T, 8); TEST_ASSIGN(T, T()); TEST_ASSIGN(T, l); TEST_ASSIGN(T, move(l)); TEST_ASSIGN(T, cl); TEST_ASSIGN(T, move(cl)); TEST_ASSIGN(T, lr); TEST_ASSIGN(T, move(lr)); TEST_ASSIGN(T, clr); TEST_ASSIGN(T, move(clr)); TEST_ASSIGN(T, rr); TEST_ASSIGN(T, move(rr)); TEST_ASSIGN(T, crr); TEST_ASSIGN(T, move(crr)); TEST_ASSIGN(T, Fcprv()); TEST_ASSIGN(T, Fprv()); TEST_ASSIGN(T, fr); TEST_ASSIGN(T, move(fr)); TEST_ASSIGN(const T, 8); TEST_ASSIGN(const T, T()); TEST_ASSIGN(const T, l); TEST_ASSIGN(const T, move(l)); TEST_ASSIGN(const T, cl); TEST_ASSIGN(const T, move(cl)); TEST_ASSIGN(const T, lr); TEST_ASSIGN(const T, move(lr)); TEST_ASSIGN(const T, clr); TEST_ASSIGN(const T, move(clr)); TEST_ASSIGN(const T, rr); TEST_ASSIGN(const T, move(rr)); TEST_ASSIGN(const T, crr); TEST_ASSIGN(const T, move(crr)); TEST_ASSIGN(const T, Fcprv()); TEST_ASSIGN(const T, Fprv()); TEST_ASSIGN(const T, fr); TEST_ASSIGN(const T, move(fr)); //TEST_ASSIGN(T&, 8); //TEST_ASSIGN(T&, T()); TEST_ASSIGN(T&, l); //TEST_ASSIGN(T&, move(l)); //TEST_ASSIGN(T&, cl); //TEST_ASSIGN(T&, move(cl)); TEST_ASSIGN(T&, lr); //TEST_ASSIGN(T&, move(lr)); //TEST_ASSIGN(T&, clr); //TEST_ASSIGN(T&, move(clr)); //TEST_ASSIGN(T&, rr); //TEST_ASSIGN(T&, move(rr)); //TEST_ASSIGN(T&, crr); //TEST_ASSIGN(T&, move(crr)); //TEST_ASSIGN(T&, Fcprv()); //TEST_ASSIGN(T&, Fprv()); TEST_ASSIGN(T&, fr); //TEST_ASSIGN(T&, move(fr)); TEST_ASSIGN(const T&, 8); TEST_ASSIGN(const T&, T()); TEST_ASSIGN(const T&, l); TEST_ASSIGN(const T&, move(l)); TEST_ASSIGN(const T&, cl); TEST_ASSIGN(const T&, move(cl)); TEST_ASSIGN(const T&, lr); TEST_ASSIGN(const T&, move(lr)); TEST_ASSIGN(const T&, clr); TEST_ASSIGN(const T&, move(clr)); TEST_ASSIGN(const T&, rr); TEST_ASSIGN(const T&, move(rr)); TEST_ASSIGN(const T&, crr); TEST_ASSIGN(const T&, move(crr)); TEST_ASSIGN(const T&, Fcprv()); TEST_ASSIGN(const T&, Fprv()); TEST_ASSIGN(const T&, fr); TEST_ASSIGN(const T&, move(fr)); TEST_ASSIGN(T&&, 8); TEST_ASSIGN(T&&, T()); //TEST_ASSIGN(T&&, l); TEST_ASSIGN(T&&, move(l)); //TEST_ASSIGN(T&&, cl); //TEST_ASSIGN(T&&, move(cl)); //TEST_ASSIGN(T&&, lr); TEST_ASSIGN(T&&, move(lr)); //TEST_ASSIGN(T&&, clr); //TEST_ASSIGN(T&&, move(clr)); //TEST_ASSIGN(T&&, rr); TEST_ASSIGN(T&&, move(rr)); //TEST_ASSIGN(T&&, crr); //TEST_ASSIGN(T&&, move(crr)); //TEST_ASSIGN(T&&, Fcprv()); TEST_ASSIGN(T&&, Fprv()); //TEST_ASSIGN(T&&, fr); TEST_ASSIGN(T&&, move(fr)); TEST_ASSIGN(const T&&, 8); TEST_ASSIGN(const T&&, T()); //TEST_ASSIGN(const T&&, l); TEST_ASSIGN(const T&&, move(l)); //TEST_ASSIGN(const T&&, cl); TEST_ASSIGN(const T&&, move(cl)); //TEST_ASSIGN(const T&&, lr); TEST_ASSIGN(const T&&, move(lr)); //TEST_ASSIGN(const T&&, clr); TEST_ASSIGN(const T&&, move(clr)); //TEST_ASSIGN(const T&&, rr); TEST_ASSIGN(const T&&, move(rr)); //TEST_ASSIGN(const T&&, crr); TEST_ASSIGN(const T&&, move(crr)); TEST_ASSIGN(const T&&, Fcprv()); TEST_ASSIGN(const T&&, Fprv()); //TEST_ASSIGN(const T&&, fr); TEST_ASSIGN(const T&&, move(fr)); //TEST_ASSIGN(auto&, T{8}); //TEST_ASSIGN(auto&, T()); TEST_ASSIGN(auto&, l); //TEST_ASSIGN(auto&, move(l)); TEST_ASSIGN(auto&, cl); TEST_ASSIGN(auto&, move(cl)); TEST_ASSIGN(auto&, lr); //TEST_ASSIGN(auto&, move(lr)); TEST_ASSIGN(auto&, clr); TEST_ASSIGN(auto&, move(clr)); TEST_ASSIGN(auto&, rr); //TEST_ASSIGN(auto&, move(rr)); TEST_ASSIGN(auto&, crr); TEST_ASSIGN(auto&, move(crr)); TEST_ASSIGN(auto&, Fcprv()); //TEST_ASSIGN(auto&, Fprv()); TEST_ASSIGN(auto&, fr); //TEST_ASSIGN(auto&, move(fr)); TEST_ASSIGN(const auto&, T{8}); TEST_ASSIGN(const auto&, T()); TEST_ASSIGN(const auto&, l); TEST_ASSIGN(const auto&, move(l)); TEST_ASSIGN(const auto&, cl); TEST_ASSIGN(const auto&, move(cl)); TEST_ASSIGN(const auto&, lr); TEST_ASSIGN(const auto&, move(lr)); TEST_ASSIGN(const auto&, clr); TEST_ASSIGN(const auto&, move(clr)); TEST_ASSIGN(const auto&, rr); TEST_ASSIGN(const auto&, move(rr)); TEST_ASSIGN(const auto&, crr); TEST_ASSIGN(const auto&, move(crr)); TEST_ASSIGN(const auto&, Fcprv()); TEST_ASSIGN(const auto&, Fprv()); TEST_ASSIGN(const auto&, fr); TEST_ASSIGN(const auto&, move(fr)); TEST_ASSIGN(auto&&, T{8}); TEST_ASSIGN(auto&&, T()); TEST_ASSIGN(auto&&, l); TEST_ASSIGN(auto&&, move(l)); TEST_ASSIGN(auto&&, cl); TEST_ASSIGN(auto&&, move(cl)); TEST_ASSIGN(auto&&, lr); TEST_ASSIGN(auto&&, move(lr)); TEST_ASSIGN(auto&&, clr); TEST_ASSIGN(auto&&, move(clr)); TEST_ASSIGN(auto&&, rr); TEST_ASSIGN(auto&&, move(rr)); TEST_ASSIGN(auto&&, crr); TEST_ASSIGN(auto&&, move(crr)); TEST_ASSIGN(auto&&, Fcprv()); TEST_ASSIGN(auto&&, Fprv()); TEST_ASSIGN(auto&&, fr); TEST_ASSIGN(auto&&, move(fr)); TEST_ASSIGN(const auto&&, T{8}); TEST_ASSIGN(const auto&&, T()); //TEST_ASSIGN(const auto&&, l); TEST_ASSIGN(const auto&&, move(l)); //TEST_ASSIGN(const auto&&, cl); TEST_ASSIGN(const auto&&, move(cl)); //TEST_ASSIGN(const auto&&, lr); TEST_ASSIGN(const auto&&, move(lr)); //TEST_ASSIGN(const auto&&, clr); TEST_ASSIGN(const auto&&, move(clr)); //TEST_ASSIGN(const auto&&, rr); TEST_ASSIGN(const auto&&, move(rr)); //TEST_ASSIGN(const auto&&, crr); TEST_ASSIGN(const auto&&, move(crr)); TEST_ASSIGN(const auto&&, Fcprv()); TEST_ASSIGN(const auto&&, Fprv()); //TEST_ASSIGN(const auto&&, fr); TEST_ASSIGN(const auto&&, move(fr)); cout << endl; const int twidth = 9; cout << left << setw(twidth) << "From:"; for (const auto& lto : tos) { cout << left << setw(twidth) << lto; } cout << endl; for (const auto& lfrom : froms) { cout << left << setw(twidth) << lfrom; for (const auto& lto : tos) { if (!res.count(lfrom) || !res[lfrom].count(lto)) { cout << left << setw(twidth) << "-"; } else if (res[lfrom][lto].empty()) { cout << left << setw(twidth) << "+"; } else { cout << left << setw(twidth) << res[lfrom][lto]; } } cout << endl; } cout << endl; } int main() { test_conversion(); cout << endl; return 0; } /* Output: Dc Dc Dc Dc Dc T = 8: Pc 8-D T = T(): Dc 1-D T = l: Cc 1-D T = move(l): Mc 1-D T = cl: Cc 1-D T = move(cl): Cc 1-D T = lr: Cc 0-D T = move(lr): Mc 0-D T = clr: Cc 0-D T = move(clr): Cc 0-D T = rr: Cc 1-D T = move(rr): Mc 1-D T = crr: Cc 1-D T = move(crr): Cc 1-D T = Fcprv(): Dc 1-D T = Fprv(): Dc 1-D T = fr: Cc 1-D T = move(fr): Mc 1-D const T = 8: Pc 8-D const T = T(): Dc 1-D const T = l: Cc 0-D const T = move(l): Mc 0-D const T = cl: Cc 1-D const T = move(cl): Cc 1-D const T = lr: Cc 0-D const T = move(lr): Mc 0-D const T = clr: Cc 0-D const T = move(clr): Cc 0-D const T = rr: Cc 0-D const T = move(rr): Mc 0-D const T = crr: Cc 1-D const T = move(crr): Cc 1-D const T = Fcprv(): Dc 1-D const T = Fprv(): Dc 1-D const T = fr: Cc 0-D const T = move(fr): Mc 0-D T& = l: 0- T& = lr: 0- T& = fr: 0- const T& = 8: Pc 8-D const T& = T(): Dc 1-D const T& = l: 0- const T& = move(l): 0- const T& = cl: 1- const T& = move(cl): 1- const T& = lr: 0- const T& = move(lr): 0- const T& = clr: 0- const T& = move(clr): 0- const T& = rr: 0- const T& = move(rr): 0- const T& = crr: 1- const T& = move(crr): 1- const T& = Fcprv(): Dc 1-D const T& = Fprv(): Dc 1-D const T& = fr: 0- const T& = move(fr): 0- T&& = 8: Pc 8-D T&& = T(): Dc 1-D T&& = move(l): 0- T&& = move(lr): 0- T&& = move(rr): 0- T&& = Fprv(): Dc 1-D T&& = move(fr): 0- const T&& = 8: Pc 8-D const T&& = T(): Dc 1-D const T&& = move(l): 0- const T&& = move(cl): 1- const T&& = move(lr): 0- const T&& = move(clr): 0- const T&& = move(rr): 0- const T&& = move(crr): 1- const T&& = Fcprv(): Dc 1-D const T&& = Fprv(): Dc 1-D const T&& = move(fr): 0- auto& = l: 0- auto& = cl: 1- auto& = move(cl): 1- auto& = lr: 0- auto& = clr: 0- auto& = move(clr): 0- auto& = rr: 0- auto& = crr: 1- auto& = move(crr): 1- auto& = Fcprv(): Dc 1-D auto& = fr: 0- const auto& = T{8}: Pc 8-D const auto& = T(): Dc 1-D const auto& = l: 0- const auto& = move(l): 0- const auto& = cl: 1- const auto& = move(cl): 1- const auto& = lr: 0- const auto& = move(lr): 0- const auto& = clr: 0- const auto& = move(clr): 0- const auto& = rr: 0- const auto& = move(rr): 0- const auto& = crr: 1- const auto& = move(crr): 1- const auto& = Fcprv(): Dc 1-D const auto& = Fprv(): Dc 1-D const auto& = fr: 0- const auto& = move(fr): 0- auto&& = T{8}: Pc 8-D auto&& = T(): Dc 1-D auto&& = l: 0- auto&& = move(l): 0- auto&& = cl: 1- auto&& = move(cl): 1- auto&& = lr: 0- auto&& = move(lr): 0- auto&& = clr: 0- auto&& = move(clr): 0- auto&& = rr: 0- auto&& = move(rr): 0- auto&& = crr: 1- auto&& = move(crr): 1- auto&& = Fcprv(): Dc 1-D auto&& = Fprv(): Dc 1-D auto&& = fr: 0- auto&& = move(fr): 0- const auto&& = T{8}: Pc 8-D const auto&& = T(): Dc 1-D const auto&& = move(l): 0- const auto&& = move(cl): 1- const auto&& = move(lr): 0- const auto&& = move(clr): 0- const auto&& = move(rr): 0- const auto&& = move(crr): 1- const auto&& = Fcprv(): Dc 1-D const auto&& = Fprv(): Dc 1-D const auto&& = move(fr): 0- From: T const T T& const T& T&& const T&&auto& const auto&auto&& const auto&& 8 PcD PcD - PcD PcD PcD - - - - T() DcD DcD - DcD DcD DcD - DcD DcD DcD l CcD CcD + + - - + + + - move(l) McD McD - + + + - + + + cl CcD CcD - + - - + + + - move(cl) CcD CcD - + - + + + + + lr CcD CcD + + - - + + + - move(lr) McD McD - + + + - + + + clr CcD CcD - + - - + + + - move(clr)CcD CcD - + - + + + + + rr CcD CcD - + - - + + + - move(rr) McD McD - + + + - + + + crr CcD CcD - + - - + + + - move(crr)CcD CcD - + - + + + + + Fcprv() DcD DcD - DcD - DcD DcD DcD DcD DcD Fprv() DcD DcD - DcD DcD DcD - DcD DcD DcD fr CcD CcD + + - - + + + - move(fr) McD McD - + + + - + + + T{8} - - - - - - - PcD PcD PcD DDDDD */ 

Inicializando referencias constantes con objetos temporales


C ++ permite inicializar una referencia constante con un objeto temporal. En este caso, se extenderá la vida útil de un objeto temporal. Ejemplo:


 struct T { int i = 1; }; const T& t = T(); cout << ti; 

Sin embargo, esta extensión de por vida funciona solo hasta el final del bloque, donde se creó el objeto temporal. Por esta razón, si un miembro de referencia constante de una clase se inicializa con un objeto temporal en un constructor, el objeto temporal se destruirá al final del constructor y la referencia continuará apuntando a un objeto destruido, que es un comportamiento indefinido:


 class A { public: // Will not compile: value-initialization of reference type //A() : t() {} const T& t; }; class B { public: // Will compile in some compilers, but temporary object will be destructed at the end of constructor B() : t(T()) { cout << "In constructor: " << ti << endl; } const T& t; }; class C { public: // Will compile, but temporary object will be destructed at the end of constructor // Address sanitizer will show the problem C() : t(std::move(T())) { cout << "In constructor: " << ti << endl; } const T& t; }; C c; cout << "C: " << cti << endl; 

Sin el desinfectante de direcciones, este programa generará basura, y con el desinfectante de direcciones se mostrará un error. Por esta razón, esta característica de C ++ no debe usarse o debe usarse con precaución.


Enlaces:
Inicialización de referencia
Referencias constantes a objetos temporales
Acerca del enlace de una referencia constante a un subobjeto de un temporal




Ir a la parte 2

Source: https://habr.com/ru/post/479342/


All Articles