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?
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]);
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
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.
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.
MyClass *ptr;
if (condition)
ptr = &object;
else
ptr = &other_object;
MyClass &ref = *ptr;
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.
}
});
}
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.