Comment déclarer une référence et initialiser plus tard

Je suis très nouveau en C++ et voici ma situation. J'ai une référence à MyOjbect, mais l'objet exact dépend d'une condition. Donc, je veux faire quelque chose comme ceci:

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

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

41
demandé sur Zaffy 2013-02-14 23:59:02

8 réponses

Vous devez l'initialiser. Mais si vous souhaitez conditionnellement l'initialiser, vous pouvez faire quelque chose comme ceci:

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);
36
répondu Zaffy 2013-02-14 20:03:05

Vous ne pouvez pas faire ça. Les références doivent être liées à quelque chose, vous ne l'aimez peut-être pas mais cela empêche toute une classe 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 pourrait être null.

Votre exemple de code ne fonctionnerait pas de toute façon car vous essayez de lier une référence non const à un objet temporaire, qui n'est pas valide.

Pourquoi en avez-vous besoin pour être 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 peut être déplacé efficacement, alors faites simplement:

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

Sinon, vous devrez mettre le code conditionnel dans une ou plusieurs fonctions, soit:

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

Ou

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

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

MyObject obj = createObject([condition]);

Ce sera probablement aussi efficace que ce que vous essayiez de faire, grâce au optimisation de la valeur de retour

11
répondu Jonathan Wakely 2013-02-14 20:30:24

AFAIK cela ne peut pas être fait avec une référence. Vous devez utiliser un pointeur:

MyClass *ptr;

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

Le pointeur agira comme une référence. N'oubliez pas d'utiliser -> pour l'accès des membres.

11
répondu 0x499602D2 2013-02-15 00:45:02

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

10
répondu 2013-02-14 20:00:00

Réponse courte: vous ne le faites pas.

Réponse légèrement plus longue: faites quelque chose comme ceci:

MyObject& getObject()
{
    if([condition]) 
        return [something] 
    else 
        return [something else];
}

MyObject& ref = getObject();

Les Avertissements habituels concernant les références s'appliquent bien sûr.

8
répondu suszterpatt 2013-02-14 20:12:03
MyClass *ptr;

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

MyClass &ref = *ptr;
4
répondu Anonymous 2015-03-27 22:59:43

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

Supposons que nous voulons un const std::string& pour une variable de sous la carte - si la carte ne contient pas de clé donnée - nous voulons jeter.

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.
    }
  });
}
1
répondu Latawiec 2018-06-18 12:23:37

Vous pouvez utiliser le mot-clé" extern": première fois (supposons, dans le fichier d'en-tête), vous pouvez déclarer votre déclaration précédente de variable avec le mot-clé" extern". Plus tard (dans le fichier source), vous répétez la déclaration sans "extern" et lui attribuez une valeur.

-1
répondu fk0 2017-04-21 14:37:48