Référence rapide des catégories de valeurs C ++: Partie 1

image

Le but de cette référence rapide est de collecter en un seul endroit et d'organiser des informations sur les catégories de valeurs en C ++, l'affectation, le passage de paramÚtres et le retour des fonctions. J'ai essayé de rendre cette référence rapide pratique pour comparer rapidement et sélectionner l'une des solutions possibles, c'est pourquoi j'ai fait plusieurs tableaux ici.


Pour une introduction au sujet, veuillez utiliser les liens suivants:


Références rvalue C ++ et déplacer la sémantique pour les débutants
Valeurs redéfinies
C ++ se déplace pour les personnes qui ne connaissent pas ou ne se soucient pas des valeurs
Scott Meyers. C ++ moderne efficace. 2015
Comprendre la sémantique de mouvement et le transfert parfait: Partie 1
Comprendre la sémantique de mouvement et le transfert parfait: partie 2
Comprendre la sémantique de mouvement et le transfert parfait: partie 3
Avons-nous besoin de déplacer et de copier l'affectation


Catégories de valeur


image


À partir de C ++ 11, toute expression ne peut appartenir qu'Ă  l'une des trois catĂ©gories de valeurs: lvalue, xvalue ou prvalue:


  • xvalue (valeur expirante) - expression, qui identifie un objet non temporaire, qui peut ĂȘtre dĂ©placĂ©
  • lvalue (valeur de gauche) - expression, qui identifie un objet de fonction non temporaire, qui ne peut pas ĂȘtre dĂ©placĂ©
  • prvalue (pure rvalue) - expression, qui initialise un objet

image


Ces trois catĂ©gories peuvent ĂȘtre regroupĂ©es en trois groupes qui se chevauchent:


  • glvalue (lvalue gĂ©nĂ©ralisĂ©e) regroupe lvalue et xvalue. glvalue a une adresse en mĂ©moire (a une identitĂ©) et peut donc gĂ©nĂ©ralement se voir attribuer une valeur (si ce n'est pas const)
  • rvalue regroupe prvalue et xvalue. rvalue peut ĂȘtre dĂ©placĂ© (xvalue) ou n'appartient pas du tout Ă  un objet existant (prvalue). rvalue peut ĂȘtre passĂ©e pour dĂ©placer des constructeurs, dĂ©placer des opĂ©rateurs d'affectation ou dĂ©placer des fonctions

Ainsi, xvalue a une adresse en mĂ©moire et peut ĂȘtre dĂ©placĂ©e.


image


Vous pouvez voir dans le tableau ci-dessus que les variables nommĂ©es de catĂ©gories lvalue, lvalue reference et rvalue reference ont toutes la mĂȘme catĂ©gorie d'expression: lvalue (surlignĂ©e en rouge). Par exemple, cela signifie que lorsque la rĂ©fĂ©rence rvalue est passĂ©e Ă  une fonction, une surcharge de rĂ©fĂ©rence lvalue sera choisie: T&& x=T(); f(x); T&& x=T(); f(x);


Liens:
C ++ lvalue rvalue xvalue glvalue prvalue
Catégories de valeurs en C ++ 17
Catégories de valeur


Abréviations dans cet article


Abréviations des constructeurs, opérateurs et destructeurs:


  • Dc - Constructeur par dĂ©faut
  • Pc - Constructeur paramĂ©trĂ©
  • Cc - Copier le constructeur
  • Ca - Affectation de copie (peut rĂ©utiliser le stockage allouĂ©, par exemple pour std :: string)
  • Mc - Constructeur Move
  • Ma - DĂ©placer l'affectation
  • Va - OpĂ©rateur d'affectation de conversion
  • D - Destructeur

Abréviations des catégories de valeurs:


  • LV - Lvalue: T LV;
  • LR - RĂ©fĂ©rence de valeur T& LR = LV; : T& LR = LV;
  • XV - Xvalue: move(LV)
  • PRV - Valeur pure. LittĂ©ral ou rĂ©sultat de l'appel de fonction, dont le type de retour n'est pas une rĂ©fĂ©rence: T f() { return T(); } T f() { return T(); }
  • FR - RĂ©fĂ©rence de transfert: auto&& FR = LV;
  • CLV - const LV. CLR - const LR. CXV - const XV.
  • CPRV - const PRV. CPRV existe uniquement pour les classes et les tableaux. Un CPRV non-classe non-tableau comme cont int sera implicitement converti en PRV comme int , par exemple en valeur de retour de la fonction const int f() )
  • RV est XV ou PRV
  • CRV est CXV ou CPRV

Autres abréviations:


  • PF - Transfert parfait (en utilisant la rĂ©fĂ©rence de transfert modĂšle pour passer le paramĂštre Ă  la fonction)

Attribution de catégories de valeurs


L'attribution de catĂ©gories de valeur peut ĂȘtre considĂ©rĂ©e comme la base de toutes les sections suivantes. Lors de l'affectation explicite d'une catĂ©gorie Ă  une autre sans conversion de catĂ©gorie explicite, une conversion implicite a lieu: FROM_TYPE x; TO_TYPE y; y = x; FROM_TYPE x; TO_TYPE y; y = x; Dans le tableau ci-dessous, vous pouvez voir ce qui se passe lorsque l'expression de type From est affectĂ©e Ă  une variable de type To:


  • Un signe moins signifie qu'une telle affectation n'est pas possible
  • Un signe plus signifie qu'une telle affectation est possible et ne nĂ©cessitera pas d'appels d'opĂ©rateurs de copie / dĂ©placement ou de constructeurs.
  • Dans d'autres cas, il y a du texte, ce qui signifie quels opĂ©rateurs de copie / dĂ©placement et constructeurs seront appelĂ©s pendant une telle affectation.

Les conversions, qui ne peuvent pas se produire implicitement de la catégorie d'expression renvoyée au type de valeur de retour de fonction, sont marquées avec une police rouge - veuillez consulter la section "Retour d'une fonction" ci-dessous pour plus de détails.
Les lignes avec des types constants sont surlignées en bleu.


image


Notes de bas de page:


1 - Les références const auto && ne sont pas des références de transfert, mais des références const rvalue, elles agiront donc comme const T &&
2 - un temporaire créé pour contenir un initialiseur de référence persiste jusqu'à la fin de la portée de sa référence (voir la section suivante). Ne fonctionne pas pour convertir la valeur de retour en type de fonction.
3 - lors du passage littéral, a besoin d'un spécificateur de type à droite pour auto: auto&& = T{2};


Remarque:


  • Les rĂ©fĂ©rences lvalue et rvalue non const ne peuvent accepter aucun type const. Mais le type non-const non-reference peut accepter les types const.
  • La rĂ©fĂ©rence de valeur (T&&) peut accepter une valeur x ou une valeur (XV ou PRV).
  • La rĂ©fĂ©rence Lvalue (T &) peut accepter la rĂ©fĂ©rence lvalue ou lvalue (LV ou LR)
  • Les types non rĂ©fĂ©rencĂ©s acceptent tous les types en convertissant, copiant, dĂ©plaçant ou RVO
  • Les rĂ©fĂ©rences const lvalue (const T &, const auto &) et les rĂ©fĂ©rences de transfert automatique (auto &&) acceptent tous les types sans copier ni dĂ©placer
  • Les rĂ©fĂ©rences de valeurs const et non const (T&&, const T&&) ne peuvent pas accepter les valeurs const ou non const l (LV ou CLV).
  • LR ne peut pas accepter les rĂ©fĂ©rences de valeur const ou non const (XV ou PRV ou CXV ou CPRV). CLR peut les accepter.
  • Les types avec des modificateurs const ne peuvent ĂȘtre attribuĂ©s Ă  aucun type sans modificateurs const (sauf auto, qui peut devenir const si const est explicite sur le cĂŽtĂ© droit).
  • Passer prvalue (passer une valeur de retour, un littĂ©ral ou un rĂ©sultat constructeur) Ă©quivaut Ă  passer xvalue, mais Ă©vite d'appeler le constructeur move lors de l'affectation Ă  un type non rĂ©fĂ©rencĂ©
  • Le passage de const prvalue (passage de la valeur de retour de la fonction de type const) est le mĂȘme que le passage de const xvalue, mais Ă©vite d'appeler le constructeur de copie lors de l'attribution Ă  un type non-rĂ©fĂ©rence
  • Les rĂ©fĂ©rences automatiques peuvent devenir const, elles peuvent donc accepter des variantes const et non const. En outre, ils peuvent devenir des rĂ©fĂ©rences const pour rendre la persistance temporaire jusqu'Ă  la fin de la portĂ©e de la rĂ©fĂ©rence. Mais les rĂ©fĂ©rences auto * ne peuvent pas devenir const si ce n'est pas spĂ©cifiĂ© explicitement sur le cĂŽtĂ© droit. C'est pourquoi vous ne pouvez pas attribuer rvalue Ă  auto &
  • La rĂ©fĂ©rence const peut recevoir un temporaire et le faire persister jusqu'Ă  la fin de la portĂ©e de rĂ©fĂ©rence (la rĂ©fĂ©rence non const ne peut pas). Cela ne fonctionne qu'Ă  l'intĂ©rieur de la portĂ©e actuelle (rĂ©fĂ©rences de fonction locale et arguments de fonction). Si la rĂ©fĂ©rence est membre d'une classe, l'objet temporaire sera dĂ©truit Ă  la fin du constructeur ou de la fonction et la rĂ©fĂ©rence continuera Ă  pointer vers un objet dĂ©truit, ce qui est un comportement non dĂ©fini.
  • Auto x = CLV; dĂ©duira auto du type non const.

Exemples et tests avec impression de chaque constructeur et opérateur appelé
 #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 */ 

Initialisation de références constantes avec des objets temporaires


C ++ permet d'initialiser une référence constante avec un objet temporaire. Dans ce cas, la durée de vie d'un objet temporaire sera prolongée. Exemple:


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

Pourtant, cette extension de durĂ©e de vie ne fonctionne que jusqu'Ă  la fin du bloc, oĂč l'objet temporaire a Ă©tĂ© crĂ©Ă©. Pour cette raison, si un membre de rĂ©fĂ©rence constant d'une classe est initialisĂ© avec un objet temporaire dans un constructeur, l'objet temporaire sera dĂ©truit Ă  la fin du constructeur et la rĂ©fĂ©rence continuera Ă  pointer vers un objet dĂ©truit, ce qui est un comportement non dĂ©fini:


 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; 

Sans dĂ©sinfectant d'adresse, ce programme affichera des dĂ©chets, et avec le dĂ©sinfectant d'adresse, une erreur sera affichĂ©e. Pour cette raison, cette fonctionnalitĂ© C ++ ne doit pas ĂȘtre utilisĂ©e ou doit ĂȘtre utilisĂ©e avec prudence.


Liens:
Initialisation de référence
Références de const aux objets temporaires
A propos de la liaison d'une référence const à un sous-objet d'un temporaire




Allez Ă  la partie 2

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


All Articles