web-dev-qa-db-fra.com

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

J'ai une référence à MyOjbect, mais l'objet exact dépend d'une condition. Je veux donc 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 pas d'initialiser une référence. Que puis-je faire pour atteindre mon objectif ici?

51
user1861088

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

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

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.

15
0x499602D2

Tu ne peux pas faire ça. Les références doivent être liées à quelque chose, vous pouvez ne pas l'aimer 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 nul.

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 de toute façon? Une solution serait de vous 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 à une valeur temporaire, si l'objet doit être non const, puis à nouveau arrêter d'essayer d'utiliser une référence:

MyObject obj = createObject([condition]);

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

14
Jonathan Wakely

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

11
user529758

Réponse courte: non.

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 exclusions habituelles concernant les références s'appliquent bien sûr.

9
suszterpatt

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

Supposons que nous voulons un const std :: string & à une variable sous la carte - si la carte ne contient pas de 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.
    }
  });
}
5
Latawiec
MyClass *ptr;

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

MyClass &ref = *ptr;
4
Anonymous

if ([condition]) MyObject & ref = MyObject ([quelque chose]); else MyObject & ref = MyObject ([autre chose]);

0
VIPK