Lorsque j'ai compilé mon code C++ avec GCC 4.3 pour la première fois, (après l'avoir compilé avec succès sans avertissements sur 4.1, 4.0, 3.4 avec le -Wall -Wextra
options) J'ai soudainement eu un tas d'erreurs de la forme warning: type qualifiers ignored on function return type
.
Considérer temp.cpp
:
class Something
{
public:
const int getConstThing() const {
return _cMyInt;
}
const int getNonconstThing() const {
return _myInt;
}
const int& getConstReference() const {
return _myInt;
}
int& getNonconstReference() {
return _myInt;
}
void setInt(const int newValue) {
_myInt = newValue;
}
Something() : _cMyInt( 3 ) {
_myInt = 2;
}
private:
const int _cMyInt;
int _myInt;
};
Fonctionnement g++ temp.cpp -Wextra -c -o blah.o
:
temp.cpp:4: warning: type qualifiers ignored on function return type
temp.cpp:7: warning: type qualifiers ignored on function return type
Quelqu'un peut-il me dire ce que je fais mal qui viole la norme C++? Je suppose que lors du retour par valeur, le premier const
est superflu, mais j'ai du mal à comprendre pourquoi il est nécessaire de générer un avertissement avec lui. Y a-t-il d'autres endroits où je devrais laisser la const?
Cela ne viole pas la norme. C'est pourquoi ils sont avertissements et non erreurs.
Et en effet, vous avez raison - le premier const
est superflu. Le compilateur vous avertit parce que vous avez ajouté du code qui, dans d'autres circonstances, pourrait signifier quelque chose, mais dans ce cas, cela ne veut rien dire, et il veut s'assurer que vous ne serez pas déçu plus tard lorsque vos valeurs de retour se révéleront être modifiables après tout.
J'ai rencontré cet avertissement lors de la compilation de code qui utilise Boost.ProgramOptions. J'utilise -Werror
donc l'avertissement tuait ma version, mais parce que la source de l'avertissement était dans les profondeurs de Boost, je ne pouvais pas m'en débarrasser en modifiant mon code.
Après beaucoup de recherches, j'ai trouvé l'option du compilateur qui désactive l'avertissement:
-Wno-ignored-qualifiers
J'espère que cela t'aides.
Le renvoi d'une valeur constante n'a de sens que lorsque vous renvoyez une référence ou un pointeur (dans ce cas, le pointeur vers constant et non un pointeur constant) car l'appelant est en mesure de modifier la valeur référencée (pointée vers).
Un autre commentaire sur le code sans rapport avec votre question: je pense qu'il vaut mieux utiliser un setter au lieu de
int& getNonconstReference() {
return _myInt;
}
Ce qui devrait être:
void setMyInt(int n) {
_myInt = n;
}
De plus, il est inutile de renvoyer une référence const à un int. Cela a du sens pour un objet plus grand dont la copie ou le déplacement est plus cher.
Ayant cela
struct Foo { Foo(int) {} operator bool() { return true; } };
et cela
Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }
l'exemple
if (some_calculation(3, 20) = 40) { /*...*/ }
compile sans avertissement. Bien sûr, c'est rare. Mais n'est-il pas exact de faire en sorte qu'il soit difficile pour les gens de mal faire les choses? Et avec l'espoir que les gens essaient des choses qui sont mauvaises, le type de retour doit être déclaré const. Et: g ++ met en garde contre l'ignorance du classificateur, mais ne l'ignore pas. Je pense que l'avertissement concerne les utilisateurs qui prennent la copie et ignorent les classificateurs const sur leur copie. Mais cela ne devrait pas être un avertissement, car c'est un comportement absolument correct. Et cela a du sens de le faire.
-Pedantic ne devrait-il pas permettre une stricte adhésion à la norme ISO? En fonction de -std = bien sûr ...
Cet avertissement est également utile pour éviter toute confusion lors de la déclaration de fonctions renvoyant des pointeurs vers des objets qui ne doivent pas être modifiés:
// "warning: type qualifiers ignored on function return type"
// as the pointer is copied.
Foo* const bar();
// correct:
const Foo* bar();
Il y a une différence entre const
sur un résultat de type basique, où il est ignoré, et const
sur un résultat de type classe, où il fait généralement des ravages.
namespace i {
auto f() -> int const { return 42; }
void g( int&& ) {}
}
namespace s {
struct S {};
auto f() -> S const { return {}; }
auto g( S&& ) {}
}
auto main() -> int
{
{ using namespace i; g( f() ); } // OK
{ using namespace s; g( f() ); } // !The `const` prevents this.
}
C'est pourquoi le compilateur met en garde dans le premier cas: c'est un cas particulier, qui peut ne pas faire ce à quoi on pourrait s'attendre naïvement.
Pour la programmation moderne, à mon humble avis, Nice serait également avec un avertissement concernant const
sur le résultat du type de classe, car il interdit le déplacement de la sémantique; un coût assez élevé pour le peu d'avantages que l'on envisageait.