Namespaces
Variants

Reference initialization

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

Lie une référence à un objet.

Table des matières

Syntaxe

Initialisation non-liste
T  & ref = target ;

T  & ref ( target );

(1)
T  && ref = target ;

T  && ref ( target );

(2) (depuis C++11)
func-refpar ( target ) (3)
return target ; (4) (dans la définition de func-refret )
Class :: Class ( ... ) : ref-member ( target ) { ... } (5) (dans la définition de Class )
Initialisation de liste ordinaire (depuis C++11)
T  & ref = { arg1 , arg2 , ... };

T  & ref { arg1 , arg2 , ... };

(1)
T  && ref = { arg1 , arg2 , ... };

T  && ref { arg1 , arg2 , ... };

(2)
func-refpar ({ arg1 , arg2 , ... }); (3)
**Note:** Since all text content in this HTML is either: - HTML tags/attributes (preserved as-is) - Code within ` ` tags (preserved as-is) - C++ specific terms (preserved as-is) - Generic programming terms (T, ref, arg1, arg2, func-refpar) that should remain in English for technical accuracy There is no translatable natural language text in this content. The structure and technical content remain identical to the original.
Initialisation de liste désignée (depuis C++20)
T  & ref = {. des1 = arg1 , . des2 { arg2 } ... };

T  & ref {. des1 = arg1 , . des2 { arg2 } ... };

(1)
T  && ref = {. des1 = arg1 , . des2 { arg2 } ... };

T  && ref {. des1 = arg1 , . des2 { arg2 } ... };

(2)
func-refpar ({. des1 = arg1 , . des2 { arg2 } ... }); (3)
**Note:** Le contenu HTML fourni ne contient aucun texte traduisible en dehors des balises ` `, `
` et ``. Tous les éléments textuels visibles sont soit :
- Des termes C++ spécifiques (T, ref, des1, arg1, etc.)
- Contenus dans des balises ``
- Des numéros de version entre parenthèses
Par conséquent, aucune traduction n'a été effectuée, conformément aux instructions.

Une référence à T peut être initialisée avec un objet de type T , une fonction de type T , ou un objet implicitement convertible en T . Une fois initialisée, une référence ne peut pas être réassignée (modifiée) pour faire référence à un autre objet.

Les références sont initialisées dans les situations suivantes :

1) Lorsqu'une variable nommée lvalue reference est déclarée avec un initialiseur.
2) Lorsqu'une variable nommée rvalue reference est déclarée avec un initialiseur.
3) Dans une expression d'appel de fonction, lorsque le paramètre de fonction a un type référence.
4) Dans l'instruction return , lorsque la fonction retourne un type référence. Le programme est mal formé si la référence retournée est liée au résultat d'une expression temporaire . (depuis C++26)
5) Lorsqu'un membre de données non statique de type référence est initialisé en utilisant un initialisateur de membre .

Explication

T - le type référencé
ref - la variable référence à initialiser
target - l'expression d'initialisation utilisée
func-refpar - une fonction avec un paramètre de type référence ( T  & ou T  && (depuis C++11) )
func-refret - une fonction dont le type de retour est un type référence ( T  & ou T  && (depuis C++11) )
Class - un nom de classe
ref-member - un membre de données non statique de type référence ( T  & ou T  && (depuis C++11) ) de Class
des1 , des2 , ... - désignateurs
arg1 , arg2 , ... - les initialiseurs dans les listes d'initialisation

Définitions

Pour deux types T1 et T2 :

  • Étant donné les versions non qualifiées cv de T1 et T2 comme U1 et U2 respectivement, si U1 est similaire à U2 , ou si U1 est une classe de base de U2 , T1 est lié par référence à T2 .
  • Si une prvalue de type « pointeur vers T2 » peut être convertie en type « pointeur vers T1 » via une séquence de conversion standard, T1 est compatible par référence avec T2 .

Règles d'initialisation

Si une initialisation de référence utilise une liste ordinaire ou désignée (depuis C++20) , les règles de l'initialisation de liste sont suivies.

(depuis C++11)

Pour l'initialisation de référence non-liste, étant donné le type de target comme U , la référence soit se lie directement à target soit se lie à une valeur de type T convertie à partir de target . La liaison directe est considérée en premier, suivie par la liaison indirecte, si aucune liaison n'est disponible, le programme est mal formé.

Dans tous les cas où la relation de compatibilité de référence de deux types est utilisée pour établir la validité d'une liaison de référence et que la séquence de conversion standard serait mal formée, un programme qui nécessite une telle liaison est mal formé.

Liaison directe

Si toutes les conditions suivantes sont satisfaites :

  • La référence à initialiser est une référence lvalue.
  • target est une lvalue non- champ de bits .
  • T est compatible par référence avec U .

Alors la référence se lie à target , ou à son sous-objet de classe de base approprié :

double d = 2.0;
double& rd = d;        // rd fait référence à d
const double& rcd = d; // rcd fait référence à d
struct A {};
struct B : A {} b;
A& ra = b;             // ra fait référence au sous-objet A dans b
const A& rca = b;      // rca fait référence au sous-objet A dans b

Sinon, si toutes les conditions suivantes sont satisfaites :

  • La référence à initialiser est une référence lvalue.
  • U est un type classe.
  • T n'est pas lié par référence à U .
  • target peut être converti en une lvalue de type V de telle sorte que T soit compatible par référence avec V .

Alors la référence se lie au résultat lvalue de la conversion, ou à son sous-objet de classe de base approprié :

struct A {};
struct B : A { operator int&(); };
int& ir = B(); // ir fait référence au résultat de B::operator int&

Sinon, si la référence à initialiser est une référence lvalue, et T n'est pas qualifié const ou est qualifié volatile, le programme est mal formé :

double& rd2 = 2.0; // erreur : pas un lvalue et la référence n'est pas const
int i = 2;
double& rd3 = i;   // erreur : incompatibilité de type et la référence n'est pas const

Sinon, si toutes les conditions suivantes sont satisfaites :

  • target est une valeur de l'une des catégories suivantes :
  • rvalue
(jusqu'à C++11)
  • xvalue non-champ de bits
  • prvalue de classe
  • prvalue de tableau
  • lvalue de fonction
(depuis C++11)
(jusqu'à C++17)
  • rvalue non-champ de bits
  • lvalue de fonction
(depuis C++17)
  • T est compatible par référence avec U .

Alors la référence se lie à target , ou à son sous-objet de classe de base approprié :

struct A {};
struct B : A {};
extern B f();
const A& rca2 = f(); // lié au sous-objet A de la valeur B temporaire.
A&& rra = f();       // identique au cas précédent
int i2 = 42;
int&& rri = static_cast<int&&>(i2); // lié directement à i2

Si target est une prvalue, la matérialisation temporaire lui est appliquée, en considérant le type de la prvalue comme étant le type ajusté P .

  • P est ajusté à partir du type de target (c'est-à-dire U ) en ajoutant la qualification cv de T à celui-ci.

Dans ce cas, la référence se lie à l'objet résultant, ou à son sous-objet de classe de base approprié.

(depuis C++17)

Sinon, si toutes les conditions suivantes sont satisfaites :

  • U est un type de classe.
  • T n'est pas lié par référence à U .
  • target peut être converti en une valeur v de type V telle que T soit compatible par référence avec V , où v est de l'une des catégories suivantes :
  • rvalue
(jusqu'à C++11)
  • xvalue
  • class prvalue
  • function lvalue
(depuis C++11)
(jusqu'à C++17)
  • rvalue
  • function lvalue
(depuis C++17)

Alors la référence se lie au résultat de la conversion, ou à son sous-objet de classe de base approprié :

struct A {};
struct B : A {};
struct X { operator B(); } x;
const A& r = x; // lié au sous-objet A du résultat de la conversion
B&& rrb = x;    // lié directement au résultat de la conversion

Si le résultat de la conversion est une prvalue, la matérialisation temporaire lui est appliquée, en considérant le type de la prvalue comme étant le type ajusté P .

  • P est ajusté à partir du type du résultat de la conversion en ajoutant la qualification cv de T à celui-ci.

Dans ce cas, la référence se lie à l'objet résultat, ou à son sous-objet de classe de base approprié.

(depuis C++17)

Liaison indirecte

Si la liaison directe n'est pas disponible, la liaison indirecte est considérée. Dans ce cas, T ne peut pas être lié par référence à U .

Si T ou U est un type classe, les conversions définies par l'utilisateur sont considérées en utilisant les règles pour l'initialisation par copie d'un objet de type T par conversion définie par l'utilisateur. Le programme est mal formé si l'initialisation par copie non-référence correspondante serait mal formée. Le résultat de l'appel à la fonction de conversion, comme décrit pour l' initialisation par copie non-référence, est ensuite utilisé pour initialiser directement la référence. Pour cette initialisation directe, les conversions définies par l'utilisateur ne sont pas considérées.

Sinon, un temporaire de type T est créé et copie-initialisé à partir de target . La référence est ensuite liée au temporaire.

(until C++17)

Sinon, target est implicitement converti en une prvalue de type « cv-unqualified T ». La conversion de matérialisation du temporaire est appliquée, en considérant le type de la prvalue comme étant T , et la référence est liée à l'objet résultant.

(since C++17)
const std::string& rs = "abc"; // rs fait référence à une copie temporaire initialisée à partir d'un tableau de caractères
const double& rcd2 = 2;        // rcd2 fait référence à une temporaire avec la valeur 2.0
int i3 = 2;
double&& rrd3 = i3;            // rrd3 fait référence à une temporaire avec la valeur 2.0

Durée de vie d'un temporaire

Chaque fois qu'une référence est liée à un objet temporaire ou à un sous-objet de celui-ci, la durée de vie de l'objet temporaire est prolongée pour correspondre à la durée de vie de la référence (vérifiez les exceptions de durée de vie des objets temporaires ), où l'objet temporaire ou son sous-objet est désigné par l'une des expressions suivantes :

(jusqu'en C++17)
(depuis C++17)

Il existe les exceptions suivantes à cette règle de durée de vie :

  • un temporaire lié à une valeur de retour d'une fonction dans une instruction return n'est pas prolongé : il est détruit immédiatement à la fin de l'expression de retour. Une telle instruction return retourne toujours une référence pendante.
(jusqu'à C++26)
  • un temporaire lié à un paramètre de référence dans un appel de fonction existe jusqu'à la fin de l'expression complète contenant cet appel de fonction : si la fonction retourne une référence, qui survit à l'expression complète, elle devient une référence pendante.
  • un temporaire lié à une référence dans l'initialiseur utilisé dans une expression new existe jusqu'à la fin de l'expression complète contenant cette expression new, et non aussi longtemps que l'objet initialisé. Si l'objet initialisé survit à l'expression complète, son membre référence devient une référence pendante.
(depuis C++11)
struct A
{
    int&& r;
};
A a1{7}; // OK, lifetime is extended
A a2(7); // well-formed, but dangling reference
(depuis C++20)

En général, la durée de vie d'un temporaire ne peut pas être prolongée davantage en « le transmettant » : une seconde référence, initialisée à partir de la variable de référence ou du membre de données auquel le temporaire était lié, n'affecte pas sa durée de vie.

Notes

Les références apparaissent sans initialiseurs uniquement dans la déclaration de paramètre de fonction, dans la déclaration de type de retour de fonction, dans la déclaration d'un membre de classe, et avec le extern spécificateur.

Jusqu'à la résolution de CWG issue 1696 , un temporaire était autorisé à être lié à un membre référence dans une initializer list d'un constructeur, et il persistait uniquement jusqu'à la sortie du constructeur, et non pas aussi longtemps que l'objet existe. Une telle initialisation est non conforme depuis CWG 1696 , bien que de nombreux compilateurs la prennent encore en charge (une exception notable est clang).

Exemple

#include <sstream>
#include <utility>
struct S
{
    int mi;
    const std::pair<int, int>& mp; // membre référence
};
void foo(int) {}
struct A {};
struct B : A
{
    int n;
    operator int&() { return n; }
};
B bar() { return B(); }
//int& bad_r;      // erreur : pas d'initialiseur
extern int& ext_r; // OK
int main()
{
//  Lvalues
    int n = 1;
    int& r1 = n;                    // référence lvalue à l'objet n
    const int& cr(n);               // la référence peut être plus cv-qualifiée
    volatile int& cv{n};            // toute syntaxe d'initialisation peut être utilisée
    int& r2 = r1;                   // autre référence lvalue à l'objet n
//  int& bad = cr;                  // erreur : moins cv-qualifiée
    int& r3 = const_cast<int&>(cr); // const_cast est nécessaire
    void (&rf)(int) = foo; // référence lvalue à fonction
    int ar[3];
    int (&ra)[3] = ar;     // référence lvalue à tableau
    B b;
    A& base_ref = b;        // référence au sous-objet de base
    int& converted_ref = b; // référence au résultat d'une conversion
//  Rvalues
//  int& bad = 1;        // erreur : impossible de lier une référence lvalue à une rvalue
    const int& cref = 1; // liée à une rvalue
    int&& rref = 1;      // liée à une rvalue
    const A& cref2 = bar(); // référence au sous-objet A du temporaire B
    A&& rref2 = bar();      // idem
    int&& xref = static_cast<int&&>(n); // liaison directe à n
//  int&& copy_ref = n;                 // erreur : impossible de lier à une lvalue
    double&& copy_ref = n;              // liée à un temporaire rvalue avec la valeur 1.0
//  Restrictions sur la durée de vie des temporaires
//  std::ostream& buf_ref = std::ostringstream() << 'a';
                     // le temporaire ostringstream était lié à l'opérande gauche
                     // de operator<< mais sa durée de vie s'est terminée au point-virgule donc
                     // buf_ref est une référence pendante
    S a {1, {2, 3}}; // paire temporaire {2, 3} liée au membre référence
                     // a.mp et sa durée de vie est étendue pour correspondre
                     // à la durée de vie de l'objet a
    S* p = new S{1, {2, 3}}; // paire temporaire {2, 3} liée au membre référence
                             // p->mp, mais sa durée de vie s'est terminée au point-virgule
                             // p->mp est une référence pendante
    delete p;
    // Imiter [[maybe_unused]] appliqué aux variables suivantes :
    [](...){}
    (
        cv, r2, r3, rf, ra, base_ref, converted_ref,
        a, cref, rref, cref2, rref2, copy_ref, xref
    );
}

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement corrigé
CWG 391 C++98 initialiser une référence vers un type qualifié const avec une rvalue
de type classe pouvait créer un temporaire, et un constructeur de cette classe
était requis pour copier la rvalue dans ce temporaire
aucun temporaire n'est
créé, le constructeur
n'est pas requis
CWG 450 C++98 une référence vers un tableau qualifié const ne pouvait pas
être initialisée avec une rvalue de tableau compatible par référence
autorisé
CWG 589 C++98 une référence ne pouvait pas se lier directement à une rvalue de tableau ou de classe autorisé
CWG 656 C++98 une référence vers un type qualifié const initialisée avec un type non
compatible par référence mais ayant une fonction de conversion vers un type
compatible par référence était liée à un temporaire copié depuis la valeur
de retour (ou son sous-objet de classe de base) de la fonction de conversion
liée directement à la valeur
de retour (ou son sous-objet
de classe de base)
CWG 1287 C++11 la conversion du target de type classe vers un autre
type compatible par référence ne pouvait être qu'implicite
autoriser les conversions
explicites
CWG 1295 C++11 une référence pouvait se lier à une xvalue de champ de bits interdit
CWG 1299 C++98 la définition de temporaire était peu claire clarifiée
CWG 1571 C++98 les conversions définies par l'utilisateur dans la liaison
indirecte ne prenaient pas en compte le type du target
pris en compte
CWG 1604 C++98 les conversions définies par l'utilisateur n'étaient pas considérées dans la liaison indirecte considérées
CWG 2352 C++98 la compatibilité par référence ne prenait pas en compte les conversions de qualification prise en compte
CWG 2481 C++17 la qualification cv n'était pas ajoutée au type de résultat
de la matérialisation de temporaire dans la liaison indirecte
ajoutée
CWG 2657 C++17 la qualification cv n'était pas ajoutée au type de résultat
de la matérialisation de temporaire dans la liaison directe
ajoutée
CWG 2801 C++98 les types liés par référence étaient autorisés pour la liaison indirecte interdit

Voir aussi