102 votes

Déclarer une référence et l'initialiser plus tard ?

J'ai une référence à une classe MyObject mais l'objet exact dépend d'une condition. Je veux faire quelque chose comme ça :

MyObject& ref; 
if([condition]) 
  ref = MyObject([something]);
else 
  ref = MyObject([something else]);

Je ne peux pas le faire pour le moment car le compilateur ne me permet pas de déclarer mais de ne pas initialiser une référence. Que puis-je faire pour atteindre mon objectif ici ?

70voto

Zaffy Points 4719

Vous devez l'initliazer. Mais si vous souhaitez l'initialiser de manière conditionnelle, vous pouvez faire quelque chose comme ceci :

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);

30voto

0x499602D2 Points 36421

AFAIK, cela ne peut pas être fait avec une référence. Il faut utiliser un pointeur :

MyClass *ptr;

if (condition)
    ptr = &object;
else
    ptr = &other_object;

Le pointeur agira de la même manière qu'une référence. N'oubliez pas d'utiliser -> pour l'accès des membres.

24voto

Latawiec Points 215

Ce que j'aime faire, c'est un lambda qui est exécuté immédiatement.

Supposons que nous voulions un const std::string& à une variable du dessous de la carte - si la carte ne contient pas la clé donnée - nous voulons lancer.

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = [&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  }(); // <- here we immediately call just created lambda.
}

Vous pouvez également utiliser std::invoke() pour le rendre plus lisible (depuis C++17)

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = std::invoke([&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  });
}

19voto

Jonathan Wakely Points 45593

Vous ne pouvez pas faire cela. Les références doivent être liées à quelque chose, cela peut ne pas vous plaire mais cela évite toute une catégorie d'erreurs, car si vous avez une référence, vous pouvez toujours supposer qu'elle est liée à quelque chose, contrairement à un pointeur qui peut être nul.

Votre exemple de code ne fonctionnerait pas de toute façon parce que vous tentez de lier une référence non-constante à un objet temporaire, ce qui n'est pas valide.

Pourquoi faut-il que ce soit une référence de toute façon ? Une solution serait de s'assurer que votre type a un constructeur par défaut peu coûteux et qu'il peut être déplacé efficacement, puis de faire simplement :

MyObject obj; 
if([condition]) 
  obj = MyObject([something]) 
else 
  obj = MyObject([something else]);

Sinon, il faudrait mettre le code conditionnel dans une ou plusieurs fonctions :

const MyObject& ref = createObject([condition]);

ou

const MyObject& ref = [condition] ? doSomething() : doSomethingElse();

Notez que ces deux versions utilisent un const référence, qui peut se lier à un temporaire, si l'objet doit être non-const, alors encore une fois arrêtez d'essayer d'utiliser une référence :

MyObject obj = createObject([condition]);

Cela sera probablement tout aussi efficace que ce que vous essayiez de faire, grâce à la fonction optimisation de la valeur de retour

13voto

En C++, vous ne pouvez pas déclarer une référence sans initialisation. Vous devez l'initialiser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X