523 Stimmen

Fehler: Übergabe von xxx als 'this'-Argument von xxx verwirft Qualifier

#include <iostream>
#include <set>

using namespace std;

class StudentT {

public:
    int id;
    string name;
public:
    StudentT(int _id, string _name) : id(_id), name(_name) {
    }
    int getId() {
        return id;
    }
    string getName() {
        return name;
    }
};

inline bool operator< (StudentT s1, StudentT s2) {
    return  s1.getId() < s2.getId();
}

int main() {

    set<StudentT> st;
    StudentT s1(0, "Tom");
    StudentT s2(1, "Tim");
    st.insert(s1);
    st.insert(s2);
    set<StudentT> :: iterator itr;
    for (itr = st.begin(); itr != st.end(); itr++) {
        cout << itr->getId() << " " << itr->getName() << endl;
    }
    return 0;
}

Im Einklang:

cout << itr->getId() << " " << itr->getName() << endl;

Er gibt eine Fehlermeldung aus:

../main.cpp:35: Fehler: Übergabe von 'const StudentT' als 'this' Argument von 'int StudentT::getId()' verwirft Qualifier

../main.cpp:35: Fehler: Übergabe von 'const StudentT' als 'this' Argument von 'std::string StudentT::getName()' verwirft Qualifier

Was ist an diesem Code falsch? Ich danke Ihnen!

15 Stimmen

Wo befindet sich Zeile 35 in Ihrem Codeschnipsel?

145 Stimmen

Ich wünschte, GCC würde diese Fehlermeldung verbessern, z.B. "discards qualifiers" -> "breaks const correctness"

15 Stimmen

@jfritz42: Das wäre verwirrend für den Fall, dass es verworfen wird. volatile

598voto

Nawaz Punkte 339767

Die Objekte im std::set werden gespeichert als const StudentT . Wenn Sie also versuchen, die getId() mit dem const Objekts erkennt der Compiler ein Problem, vor allem, dass Sie eine Nicht-Konst-Mitgliedsfunktion auf einem Konst-Objekt aufrufen, was nicht erlaubt ist, da Nicht-Konst-Mitgliedsfunktionen KEIN Versprechen abgeben, das Objekt nicht zu verändern; daher wird der Compiler eine sicher Annahme, dass getId() könnte versuchen, das Objekt zu ändern, aber gleichzeitig merkt es auch, dass das Objekt const ist; daher sollte jeder Versuch, das const-Objekt zu ändern, einen Fehler darstellen. Daher erzeugt der Compiler eine Fehlermeldung.

Die Lösung ist einfach: Machen Sie die Funktionen const as:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Dies ist notwendig, weil Sie jetzt die Funktion getId() y getName() auf const-Objekte als:

void f(const StudentT & s)
{
     cout << s.getId();   //now okay, but error with your versions
     cout << s.getName(); //now okay, but error with your versions
}

Nebenbei bemerkt, sollten Sie die operator< als:

inline bool operator< (const StudentT & s1, const StudentT & s2)
{
    return  s1.getId() < s2.getId();
}

Die Notizparameter sind jetzt const Hinweis.

3 Stimmen

Eine so klare Erklärung. Danke. Aber ich wundere mich über Ihren letzten Codeschnipsel. Warum verwenden Sie eine Referenz im Funktionsparameter? const StudentT & s1, const StudentT & s2 ?

3 Stimmen

@RafaelAdel: Sie verwenden Referenzen, um unnötige Kopien zu vermeiden, und const weil die Funktion das Objekt nicht verändern muss, so dass die const erzwingt dies zur Kompilierzeit.

100voto

Fred Larson Punkte 58721

Mitgliedsfunktionen, die die Klasseninstanz nicht verändern, sollten als const :

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Jedes Mal, wenn Sie "Discards Qualifiers" sehen, ist damit Folgendes gemeint const o volatile .

2 Stimmen

@Fred - Meinen Sie, dass es unbedingt erforderlich ist, const-Modifikatoren zu Mitgliedsfunktionen hinzuzufügen, die keine Klasseninstanz verändern? Gibt es einen anderen Grund für den Fehler in diesem Fall? Ich bezweifle es, denn in den meisten Gettern, die ich schreibe, füge ich keine Const-Modifikatoren hinzu.

0 Stimmen

@Mahesh: Ja, es ist Teil der Konstante Korrektheit . Ich bin mir nicht sicher, wo die const kommt von hier, aber ich vermute, dass die set eine Konstantenreferenz aus dem Iterator zurück, um zu verhindern, dass sich die Instanz ändert und dadurch die Menge ungültig wird.

0 Stimmen

@Mahesh: Würde meine Codeüberprüfung nicht bestehen. Ich habe einen Kollegen, der mich als "Constable" bezeichnet. 8v) Ändern Sie das foo obj; à const foo obj; und sehen, was passiert. Oder übergeben Sie eine const Verweis auf eine foo .

9voto

Eigentlich ist der C++-Standard (d.h. C++ 0x Entwurf ) sagt (danke an @Xeo & @Ben Voigt für den Hinweis):

23.2.4 Assoziative Container
5 Bei Set und Multiset ist der Wertetyp derselbe wie der Schlüsseltyp. Bei map und multimap ist er gleich dem Typ pair. Die Schlüssel in einem assoziativen Container sind unveränderlich.
6 Iterator von eines assoziativen Containers ist von der Kategorie der bidirektionalen Iteratoren. Für assoziativen Containern, bei denen der Wert Typ derselbe ist wie der Schlüsseltyp, sind sowohl iterator und const_iterator sind konstante Iteratoren. Es ist nicht spezifiziert ob iterator und const_iterator derselbe Typ sind.

Die Implementierung von VC++ 2008 Dinkumware ist also fehlerhaft.


Alte Antwort:

Sie haben diesen Fehler, weil in bestimmten Implementierungen der std lib die set::iterator ist dasselbe wie set::const_iterator .

Zum Beispiel hat libstdc++ (mit g++ ausgeliefert) es (siehe aquí für den gesamten Quellcode):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;

Und in SGI's docs heißt es:

iterator       Container  Iterator used to iterate through a set.
const_iterator Container  Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)

Andererseits kompiliert VC++ 2008 Express Ihren Code, ohne sich darüber zu beschweren, dass Sie nichtkonstante Methoden auf set::iterator s.

5voto

Jayhello Punkte 4867

Lassen Sie mich ein ausführlicheres Beispiel geben. Wie bei der untenstehenden Struktur:

struct Count{
    uint32_t c;

    Count(uint32_t i=0):c(i){}

    uint32_t getCount(){
        return c;
    }

    uint32_t add(const Count& count){
        uint32_t total = c + count.getCount();
        return total;
    }
};

enter image description here

Wie Sie oben sehen, wird die IDE (CLion), Tipps geben Non-const function 'getCount' is called on the const object . Bei der Methode add count ist als const object deklariert, aber die Methode getCount ist keine const-Methode, also count.getCount() kann die Mitglieder in count .

Kompilierfehler wie unten (Kernmeldung in meinem Compiler):

error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]

Sie können das obige Problem folgendermaßen lösen:

  1. die Methode ändern uint32_t getCount(){...} zu uint32_t getCount() const {...} . Donc count.getCount() ändert nicht die Mitglieder in count .

ou

  1. ändern uint32_t add(const Count& count){...} a uint32_t add(Count& count){...} . Donc count sich nicht um den Wechsel von Mitgliedern in der Gruppe kümmern.

Was Ihr Problem betrifft, so werden die Objekte in std::set als const StudentT gespeichert, aber die Methode getId y getName sind nicht const, so dass Sie den oben genannten Fehler erhalten.

Sie können auch diese Frage sehen Bedeutung des letzten Wortes "const" in einer Funktionserklärung einer Klasse? für weitere Einzelheiten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X