Pedantische gcc-Warnung: Geben Sie Qualifikationsmerkmale für den Funktionsrückgabetyp ein

75

Als ich meinen C ++ - Code zum ersten Mal mit GCC 4.3 kompilierte (nachdem ich ihn erfolgreich ohne Warnungen in 4.1, 4.0, 3.4 mit den -Wall -WextraOptionen kompiliert hatte ), bekam ich plötzlich eine Reihe von Fehlern im Formular warning: type qualifiers ignored on function return type.

Bedenken Sie 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;
};

Laufen 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

Kann mir jemand sagen, was ich falsch mache, was gegen den C ++ - Standard verstößt? Ich nehme an, dass bei der Rückkehr nach Wert die Führung constüberflüssig ist, aber ich habe Probleme zu verstehen, warum es notwendig ist, damit eine Warnung zu generieren. Gibt es andere Orte, an denen ich die Konstante weglassen sollte?

Seth Johnson
quelle
Siehe diese ähnliche Frage und Antworten: stackoverflow.com/questions/1607188/…
Johannes Schaub - litb
16
Ich habe schon einmal solche Warnungen gesehen, aber ich habe einige Minuten lang versucht zu verstehen, was in meinem Code vor sich geht. Wahrscheinlich würde eine bessere Fehlerberichterstattung die Dinge beschleunigen. Anstelle von so warning: type qualifiers ignored on function return typeetwas warning: please don't add const qualifier when you are returning by value.
Avio
@ Avio Warum sollten wir das constQualifikationsmerkmal nicht zur Funktion hinzufügen , die einen Wert zurückgibt ? Wir tun dies, weil wir nicht möchten, dass sich der Wert danach ändern kann.
Franky
@Franky const int foo (); <- const ist nutzlos. Tut buchstäblich nichts. const int & foo (); <- const ist sinnvoll.
Jonesmz

Antworten:

100

Es verstößt nicht gegen den Standard. Deshalb sind sie Warnungen und keine Fehler .

Und in der Tat haben Sie Recht - die Führung constist ü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 nichts bedeutet, und er möchte sicherstellen, dass Sie später nicht enttäuscht werden, wenn sich Ihre Rückgabewerte schließlich als änderbar herausstellen.

Rob Kennedy
quelle
20
Dass es warnt und keine Fehler, bedeutet nichts. Andere ungültige Codes wie sizeof(void)warnen ebenfalls nur, sind aber eindeutig verboten. Der Standard kennt den Unterschied zwischen Warnungen und Fehlern nicht: Beide sind Diagnosen.
Johannes Schaub - litb
3
@litb: Was er gesagt hat ist immer noch richtig. Natürlich garantiert die Tatsache, dass es sich um Warnungen handelt, nicht , dass sie nicht gegen den Standard verstoßen, wie Sie sagen, aber der Grund , warum sie Warnungen anstelle von Fehlern machen, ist, dass die Compiler-Implementierer dies nicht verbieten wollten. 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
Ich denke, mein erster Satz war ziemlich klar, @Philipp. Schauen Sie sich die Frage an, die Johannes im Fragekommentar erwähnt hat: Warum ist ein Typqualifizierer für einen Rückgabetyp bedeutungslos?
Rob Kennedy
20

Diese Warnung ist beim Kompilieren von Code mit Boost.ProgramOptions aufgetreten. Ich benutze es, -Werrordamit die Warnung meinen Build beendet, aber da die Quelle der Warnung in den Tiefen von Boost lag, konnte ich sie nicht durch Ändern meines Codes beseitigen.

Nach langem Suchen habe ich die Compiler-Option gefunden, die die Warnung deaktiviert:

-Wno-ignored-qualifiers

Hoffe das hilft.

ccaughie
quelle
8
Ich hatte das gleiche Problem und setzte schließlich den Include-Pfad von Boost mit -isystemanstelle von -I, wodurch alle von Boost-Headern ausgelösten Warnungen unterdrückt werden.
Philipp
1
@ Philipps Lösung ist die richtige. Die Verwendung von -Wno-ignore-Qualifiers wirkt sich auf Ihren Code aus und verhindert, dass Ihr Compiler von Ihnen erstellte Warnungen ausgibt, während die Lösung von Philipp keine Auswirkungen auf Warnungen hat, die von Ihrem eigenen Code erzeugt werden.
Wond3rBoi
7

Die Rückgabe eines konstanten Werts ist nur sinnvoll, wenn Sie eine Referenz oder einen Zeiger (in diesem Fall einen Zeiger auf eine Konstante und keinen konstanten Zeiger) zurückgeben, da der Aufrufer den referenzierten Wert (auf den verwiesen wird) ändern kann.

Ein weiterer Kommentar zum Code, der nicht mit Ihrer Frage zusammenhängt: Ich denke, es ist besser, einen Setter anstelle von zu verwenden

int& getNonconstReference() {
    return _myInt;
}

Welcher Wille sollte sein:

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

Darüber hinaus ist es sinnlos, eine const-Referenz auf ein int zurückzugeben. Dies ist sinnvoll für ein größeres Objekt, dessen Kopieren oder Verschieben teurer ist.

Brahim
quelle
2

Das haben

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

und das

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

das Beispiel

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

Kompiliert ohne Vorwarnung. Das ist natürlich selten. Aber ist es nicht richtig, es den Menschen schwer zu machen, Dinge falsch zu machen? Und mit der Erwartung, dass Leute Dinge ausprobieren, die falsch sind, sollte der Rückgabetyp als const deklariert werden. Und: g ++ warnt vor dem Ignorieren des Klassifikators, ignoriert ihn jedoch nicht. Ich denke, die Warnung bezieht sich auf Benutzer, die die Kopie nehmen und die const-Klassifizierer auf ihrer Kopie ignorieren. Dies sollte jedoch keine Warnung sein, da dies ein absolut korrektes Verhalten ist. Und das macht Sinn.

mcbulba
quelle
3
G ++ würde hier nicht warnen, wenn Sie a hinzufügen const. Das constQualifikationsmerkmal wird nur für Rückgabewerte vom Typ Nichtklasse ignoriert.
Philipp
1

Sollte -pedantic nicht nur die strikte Einhaltung des ISO-Standards erlauben? Abhängig von -std = natürlich ...

Steve
quelle
1

Diese Warnung ist auch nützlich, um Verwirrung zu vermeiden, wenn Funktionen deklariert werden, die Zeiger auf Objekte zurückgeben, die nicht geändert werden sollten:

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

// correct:
const Foo* bar();
Luchs
quelle
0

Es gibt einen Unterschied zwischen consteinem Basistyp-Ergebnis, bei dem es ignoriert wird, und consteinem Klassentyp-Ergebnis, bei dem es im Allgemeinen Chaos anrichtet.

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

Aus diesem Grund warnt der Compiler im ersten Fall: Es ist ein Sonderfall, der möglicherweise nicht das tut, was man naiv erwarten kann.

Für die moderne Programmierung wäre es meiner Meinung nach auch nett, eine Warnung über das constKlassentyp-Ergebnis zu erhalten, da es die Bewegungssemantik verbietet. ziemlich hohe Kosten für jeden kleinen Vorteil, den man sich vorgestellt hatte.

Prost und hth. - Alf
quelle
-5

Scott Meyers wies darauf hin, dass es einen guten Grund gibt, warum jemandconstWerte zurückgebenmö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)
{

}

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

Mit einem constRückgabewert wird das obige Beispiel nicht kompiliert. Zumindest, wenn der Compiler das constSchlüsselwort nicht verwirft .

user321269
quelle
15
Nein, es sollte nicht kompiliert werden. Das Ergebnis von some_calculationist ein Wert vom Typ int. Sie können keine Werte vom Typ Nichtklasse zuweisen.
CB Bailey
1
Und wenn der Rückgabewert vom Klassentyp ist, constist er korrekt und generiert keine Warnung.
Philipp
Haben Sie tatsächlich versucht, dieses Beispiel zu kompilieren? GCC gibt "Fehler: Wert als linker Operand der Zuweisung erforderlich", clang ++ gibt "Fehler: Ausdruck ist nicht zuweisbar"
Bulletmagnet
Er meinte wahrscheinlich==
user1032677