2009-07-15 7 views
56

Als ich meinen C++ Code mit GCC 4.3 zum ersten Mal kompiliert habe (nachdem ich ihn ohne Warnungen auf 4.1, 4.0, 3.4 mit den -Wall -Wextra Optionen kompiliert habe), bin ich plötzlich gekommen eine Reihe von Fehlern der Form warning: type qualifiers ignored on function return type.Pedantic gcc Warnung: Typ Qualifier auf Funktion Rückgabetyp

Betrachten 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; 
}; 

g++ temp.cpp -Wextra -c -o blah.o Laufen:

temp.cpp:4: warning: type qualifiers ignored on function return type 
temp.cpp:7: warning: type qualifiers ignored on function return type 

Kann mir jemand sagen, was ich falsch mache, dass die C++ Standard verletzt? Ich nehme an, dass bei der Rückgabe nach Wert der führende const überflüssig ist, aber ich habe Probleme zu verstehen, warum es notwendig ist, eine Warnung damit zu generieren. Gibt es noch andere Orte, wo ich die Const verlassen sollte?

+0

Ähnliche Fragen und Antworten finden: http://stackoverflow.com/questions/1607188/why-is-type-qualifier-on-return-type-is-meaningless –

+7

Ich habe solche Warnungen schon einmal gesehen Ich habe mehrere Minuten damit verbracht zu verstehen, was in meinem Code vor sich ging. Wahrscheinlich würde eine bessere Fehlerberichterstattung die Dinge beschleunigen. Anstelle von 'warning: type qualifiers wird bei der Funktion 'return type' ignoriert, so etwas wie' warning: Bitte fügen Sie kein const-Qualifikationsmerkmal hinzu, wenn Sie nach Wert zurückgeben'. – Avio

Antwort

77

Es verletzt nicht den Standard. Deshalb sind sie Warnungen und nicht Fehler.

Und in der Tat hast du Recht - die führende const ist überflüssig. Der Compiler warnt Sie, weil Sie Code hinzugefügt haben, der unter anderen Umständen etwas bedeuten könnte, aber unter diesen Umständen bedeutet das nichts, und er möchte sicherstellen, dass Sie später nicht enttäuscht werden, wenn sich Ihre Rückgabewerte als veränderbar herausstellen.

+13

Dass es warnt und nicht Fehler bedeutet nichts.Anderer ungültiger Code wie 'sizeof (void)' warnt lediglich, ist aber eindeutig verboten. Der Standard kennt den Unterschied zwischen Warnungen und Fehlern nicht: Beide sind Diagnosen. –

+1

@litb: Was er gesagt hat, ist immer noch richtig. Natürlich garantiert die Tatsache, dass sie Warnungen sind, nicht, dass es nicht gegen den Standard verstößt, wie du sagst, aber der Grund dafür, dass sie Warnungen anstelle von Fehlern sind, ist, dass die Compiler-Implementierer das nicht verbieten wollten es. Und der Grund, warum sie es nicht verbieten wollten, ist, dass es nicht gegen den Standard verstößt. – jalf

+1

Verstößt es überhaupt gegen den Standard? – Philipp

17

Ich habe diese Warnung beim Kompilieren von Code gefunden, der Boost.ProgramOptions verwendet. Ich benutze -Werror, so dass die Warnung mein Build tötete, aber weil die Quelle der Warnung in den Tiefen von Boost war, konnte ich sie nicht loswerden, indem ich meinen Code änderte.

Nach viel Graben fand ich die Compiler-Option, die die Warnung deaktiviert:

-Wno-ignored-qualifiers 

Hoffnung, das hilft.

+4

Ich hatte das gleiche Problem und endete damit, Boost's Include-Pfad mit '-isystem' anstelle von' -I' zu setzen, was alle Warnungen unterdrückt, die von Boost-Headern ausgelöst wurden. – Philipp

+0

@ Philipps Lösung ist die richtige. Die Verwendung von "-no-ignored-qualifiers" wirkt sich auf Ihren Code aus und verhindert, dass Ihr Compiler die von Ihnen erstellten Warnungen ausgibt, während die Lösung von Philipp sich nicht auf Warnungen auswirkt, die durch Ihren eigenen Code erzeugt werden. – Wond3rBoi

-5

Scott Meyers wies darauf hin, dass es ziemlich guten Grund gibt, warum jemand const Werte zurückgeben möchte. Hier ist ein Beispiel:

int some_calculation(int a, int b) { int res = 0; /* ... */ return res; } 

/* Test if the result of the calculation equals 40.*/ 
if (some_calculation(3,20) = 40) 
{ 

} 

Siehst du, was ich falsch gemacht habe? Dieser Code ist absolut korrekt und sollte kompiliert werden. Das Problem besteht darin, dass der Compiler nicht verstanden hat, dass Sie vergleichen möchten, anstatt den Wert 40 zuzuweisen.

Mit einem const Rückgabewert wird das obige Beispiel nicht kompiliert. Nun, zumindest wenn der Compiler das const Schlüsselwort nicht verwerfen wird.

+14

Nein, es sollte nicht kompiliert werden. Das Ergebnis von 'some_calculation' ist ein Rvalue vom Typ int. Sie können rValues ​​vom Nicht-Klassen-Typ nicht zuweisen. –

+1

Und wenn der Rückgabewert vom Typ der Klasse ist, ist das 'const' korrekt und erzeugt keine Warnung. – Philipp

+0

Haben Sie tatsächlich versucht, dieses Beispiel zu kompilieren? GCC gibt "Fehler: Lvalue erforderlich als linker Operand der Zuweisung", clang ++ gibt "Fehler: Ausdruck ist nicht zuweisbar" – Bulletmagnet

2

Mit diesen

struct Foo { Foo(int) {} operator bool() { return true; } };

und dass

Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }

das Beispiel

if (some_calculation(3, 20) = 40) { /*...*/ }

ohne eine Warnung erstellt. Natürlich ist das selten. Aber ist es nicht richtig, Leuten die Möglichkeit zu geben, etwas falsch zu machen? Und mit der Erwartung, dass Menschen Dinge versuchen, die falsch sind, sollte der Rückgabetyp const genannt werden. Und: g ++ warnt davor, den Klassifikator zu ignorieren, ignoriert ihn aber nicht. Ich denke, die Warnung bezieht sich auf Benutzer, die die Kopie nehmen und die const-Klassifizierer auf ihrer Kopie ignorieren. Aber das sollte keine Warnung sein, denn das ist absolut korrektes Verhalten. Und es macht Sinn, dies zu tun.

+3

G ++ würde hier nicht warnen, wenn Sie eine 'const' hinzugefügt. Das 'const'-Qualifikationsmerkmal wird nur für Rückgabewerte vom Typ Nicht-Klasse ignoriert. – Philipp

1

Sollte -pedantisch nur die strikte Einhaltung des ISO-Standards erlauben? Je nach -std = natürlich ...

1

Diese Warnung ist auch nützlich, um Verwirrung zu vermeiden, wenn Funktionen erklären Zeiger auf Objekte zurückkehren, das modifiziert werden soll:

// "warning: type qualifiers ignored on function return type" 
// as the pointer is copied. 
Foo* const bar(); 

// correct: 
const Foo* bar(); 
4

nur einen konstanten Wert zurückkehrend Sinn macht, wenn Sie geben eine Referenz oder einen Zeiger zurück (in diesem Fall Zeiger auf Konstante und nicht auf einen konstanten Zeiger), da der Aufrufer den referenzierten (auf) Wert ändern kann.

Ein weiterer Kommentar über den Code nicht zu Ihrer Frage: Ich denke, es ist besser, statt

int& getNonconstReference() { 
    return _myInt; 
} 

einen Setter zu verwenden, die werden sollte:

void setMyInt(int n) { 
    _myInt = n; 
} 

Darüber hinaus ist es nutzlos zu Gibt einen const-Verweis auf einen int zurück. Es macht Sinn für ein größeres Objekt, dessen Kopie oder Umzug teurer ist.

0

Es gibt einen Unterschied zwischen const bei einem Basistyp-Ergebnis, bei dem es ignoriert wird, und const bei einem Klassentyp-Ergebnis, bei dem es im Allgemeinen Schaden anrichtet. Diese

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. 
} 

ist, warum die Compiler im ersten Fall warnen: es ist ein Sonderfall, die nicht tun, was man naiverweise erwarten konnte.

Für die moderne Programmierung wäre es IMHO nett auch mit einer Warnung über const auf Klassenergebnis, da es Bewegungssemantik verbietet; eine ziemlich hohe Kosten für den kleinen Vorteil, den man sich vorgestellt hatte.