HOWTO · C++
Comment résoudre l'erreur « control reaches end of non-void function » en C++
Découvrez pourquoi une fonction C++ non void peut atteindre son accolade fermante, comment couvrir chaque chemin de retour et quand une valeur de repli ou un avertissement du compilateur peut aider.
Sur cette page
Une fonction C++ dont le type de retour n’est pas void doit produire une valeur sur chaque chemin atteignable. La seule exception est la fin de main, qui renvoie implicitement 0. Si, dans une autre fonction non void, un chemin atteignable atteint l’accolade fermante sans valeur return, le comportement est indéfini. Selon le code et les options d’avertissement, le compilateur peut également signaler ce chemin. Pour corriger le problème, examinez chaque branche et faites correspondre sa valeur de retour au rôle de la fonction.
Comprendre l’erreur
Une fonction non void promet une valeur du type qu’elle déclare. Le diagnostic du compilateur souvent appelé « control reaches end of non-void function » signale un chemin qui peut atteindre l’accolade fermante sans renvoyer cette valeur. Le problème ne se résume pas à une instruction manquante à la fin : une condition précédente peut laisser certains cas sans résultat. Par exemple, int add(int a, int b) { if (a > b) return a + b; } ne renvoie aucune valeur lorsque a <= b. Si une fonction non void autre que main atteint ainsi sa fin, le comportement est indéfini : cela ne garantit ni plantage ni résultat particulier.
Exécutez cet exemple :
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
std::cout << add(5, 3) << '\n';
}
8
Le programme renvoie la somme pour cette entrée. La version intégrée ci-dessus montre la cause du diagnostic ; la version exécutable corrige le problème en renvoyant une valeur pour chaque entrée.
S’assurer que tous les chemins renvoient une valeur
Examinez les conditions et déterminez ce que chaque cas doit produire. Pour une addition, les deux ordres des opérandes doivent donner leur somme. Si la condition sert à effectuer un autre traitement, un return final peut couvrir le chemin restant. Si les deux branches font la même chose, supprimez la condition :
#include <iostream>
int add(int a, int b) {
if (a > b) {
return a + b;
}
return a + b;
}
int main() {
std::cout << add(3, 5) << '\n';
}
Une structure complète de branches est utile lorsque les cas ont des significations différentes. Cet exemple renvoie le plus grand opérande et couvre les deux chemins :
#include <iostream>
int larger(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
int main() {
std::cout << larger(5, 3) << '\n';
}
Vérifiez aussi les conditions imbriquées et les instructions switch : chaque chemin dans une fonction non void doit renvoyer une valeur ou éviter d’atteindre l’accolade fermante.
Utiliser des valeurs de retour par défaut
Un return final peut servir de solution de repli pour les cas qui ne correspondent à aucune condition précédente. N’utilisez cette valeur que si elle respecte le contrat de la fonction. Par exemple, cette recherche renvoie le score connu lorsque le nom correspond et 0 lorsque le nom est absent ; ce repli n’est approprié que si l’application définit le score absent comme égal à zéro.
#include <iostream>
#include <string>
int scoreFor(const std::string& name) {
if (name == "Ada") {
return 10;
}
return 0;
}
int main() {
std::cout << scoreFor("Ada") << '\n';
std::cout << scoreFor("Lin") << '\n';
}
Si l’absence constitue un résultat distinct, renvoyer 0 peut masquer cette différence. Choisissez un type de retour et un résultat qui expriment le contrat réel, par exemple une valeur optionnelle ou un état explicite. N’ajoutez pas une valeur de repli arbitraire dans le seul but de faire disparaître un diagnostic.
Déboguer à l’aide des avertissements du compilateur
Activez les avertissements lors de la compilation afin que le compilateur puisse vous aider à repérer un chemin à examiner. Par exemple, g++ -Wall -Wextra -Wreturn-type your_code.cpp -o your_program demande à GCC de signaler différents avertissements, notamment ceux qui concernent les chemins de retour lorsque c’est applicable. La disponibilité et la formulation des avertissements varient selon le compilateur, sa version, les options et le code. Un avertissement est une indication qui invite à suivre le flux de contrôle, et non la preuve que tous les compilateurs traitent le code de la même façon.
Examinez chaque branche, y compris les instructions if imbriquées et tous les cas de switch. Déterminez ensuite le comportement attendu de la fonction pour chaque entrée et renvoyez une valeur conforme. Laissez les avertissements activés pendant le développement pour repérer plus facilement les chemins similaires.
Conclusion
Lorsqu’une fonction C++ non void peut atteindre son accolade fermante sans produire de valeur, suivez ce chemin et corrigez la logique de la fonction. Couvrez chaque cas avec un return adapté à son rôle. N’utilisez une valeur de repli que si elle a une signification définie, et servez-vous des avertissements du compilateur pour repérer les chemins à examiner.
FAQ
Quelle est la cause du diagnostic « control reaches end of non-void function » ?
Un chemin atteignable dans une fonction qui renvoie une valeur atteint l’accolade fermante sans renvoyer de valeur. Les compilateurs peuvent signaler cette situation, mais le diagnostic et le comportement de la compilation dépendent du compilateur et de ses options.
Chaque branche if doit-elle contenir un return ?
Non. Un return placé après la condition peut traiter le chemin restant. L’essentiel est qu’aucun chemin atteignable ne termine la fonction sans valeur.
Dois-je ajouter return 0; pour faire disparaître l’avertissement ?
Seulement si zéro est un résultat valide selon le contrat de la fonction. Sinon, choisissez un résultat ou un type de retour qui représente correctement le cas manquant.
Un avertissement du compilateur peut-il repérer le chemin manquant ?
Il peut signaler une fonction susceptible d’atteindre sa fin. Servez-vous-en pour examiner le flux de contrôle ; le texte et le comportement des avertissements varient selon les compilateurs et les paramètres.