エラー:xxxの「this」引数としてxxxを渡すと修飾子が破棄されます


457
#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;
}

列をなして:

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

次のエラーが発生します。

../main.cpp:35:エラー:「const StudentT」を「int StudentT :: getId()」の「this」引数として渡すと、修飾子が破棄されます

../main.cpp:35:エラー: 'std :: string StudentT :: getName()'の 'this'引数として 'const StudentT'を渡すと修飾子が破棄されます

このコードの何が問題になっていますか?ありがとうございました!


13
コードスニペットの35行目はどこにありますか?
インシリコ

118
GCCでこのエラーメッセージが改善されることを望みます。たとえば、「
discards

13
@ jfritz42:破棄する場合は混乱しますvolatile
PlasmaHH 2013

3
@PlasmaHHエラーメッセージは、「constの正確さを壊す」と「揮発性の正確さを壊す」に分割されます。さて、揮発性の正しい
Caleth

回答:


524

のオブジェクトはstd::setとして保存されconst StudentTます。そのためgetId()constオブジェクトを使用して呼び出そうとすると、コンパイラーが問題を検出します。主に、constオブジェクトの非constメンバー関数を呼び出しています。これは、非constメンバー関数がオブジェクトを変更しないようにするため、許可されていません。そのため、コンパイラーはオブジェクトを変更しようとする可能性のある安全な仮定をgetId()行いますが、同時に、オブジェクトがconstであることに気づきます。したがって、constオブジェクトを変更しようとすると、エラーになります。したがって、コンパイラはエラーメッセージを生成します。

解決策は簡単です:関数を次のようにconstにします:

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

これが必要なのは、次のようにgetId()getName()てconstオブジェクトを呼び出すことができるからです。

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
}

補足として、次のように実装する必要がありますoperator<

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

注:パラメータはconst参照用です。


3
そのような明確な説明。ありがとう。しかし、私はあなたの最後のコードスニペットについて疑問に思います。関数パラメーターで参照を使用する理由 const StudentT & s1, const StudentT & s2
Rafael Adel

2
@RafaelAdel:不要なコピーを回避するために参照を使用します。const関数はオブジェクトを変更する必要がないため、constはコンパイル時にこれを強制します。
Nawaz

90

クラスインスタンスを変更しないメンバー関数は、const次のように宣言する必要があります。

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

「修飾子を破棄する」と表示されるときはいつでも、constまたはのことvolatileです。


2
@Fred-クラスインスタンスを変更しないメンバー関数にconst修飾子を追加することは間違いなく要件だと思いますか?この場合、エラーの他の理由はありますか?私が書いているほとんどのゲッターでは、const修飾子を追加していないので、疑問に思います。
Mahesh、

@Mahesh:はい、これはconstの正当性の一部です。constがどこから来ているのかはわかりませんがset、インスタンスが変更されてセットが無効になるのを防ぐために、イテレータからconst参照が返されていると思います。
Fred Larson、

@Mahesh:コードレビューに合格しない。「const-able」と呼んでくれる同僚がいます。8v)これfoo obj;const foo obj;1回に変更して、何が起こるかを確認します。または、constへの参照を渡しfooます。
Fred Larson、

3
@Mahesh:それは私が言ったようなものです-aの要素setが変更されると、順序が狂う可能性があり、そのセットはもう有効ではありません。ではmap、キーのみですconst。では、setオブジェクト全体が本当に重要です。
Fred Larson、

1
@Mahesh:constが必要です。それ以外の場合は、constオブジェクトで呼び出すことはできません。f()私の答えで機能を参照してください。
Nawaz、

5

実際、C ++標準(つまり、C ++ 0xドラフト)は次のように述べています(@Xeoと@Ben Voigtにtnxで指摘してくれます):

23.2.4連想コンテナ
5セットおよびマルチセットの場合、値のタイプはキーのタイプと同じです。マップとマルチマップの場合、ペアに相当します。連想コンテナのキーは不変です。
6連想コンテナの反復子は、双方向反復子カテゴリです。値のタイプがキーのタイプと同じである連想コンテナの場合、イテレータとconst_iteratorはどちらも定数イテレータです。イテレータとconst_iteratorが同じ型であるかどうかは不定です。

そのため、VC ++ 2008 Dinkumwareの実装に欠陥があります。


古い答え:

std libの特定の実装でset::iteratorはと同じであるため、このエラーが発生しましたset::const_iterator

たとえば、libstdc ++(g ++に付属)にはそれがあります(ソースコード全体については、こちらを参照してください)。

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

そして、SGIのドキュメントにはそれは述べています:

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

一方、VC ++ 2008 Expressは、非constメソッドを呼び出していることを訴えずにコードをコンパイルします。 set::iterator sで。


2

より詳細な例を挙げましょう。以下の構造体について:

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

ここに画像の説明を入力してください

上記のように、IDE(CLion)がヒントを提供しますNon-const function 'getCount' is called on the const object。メソッドでadd countはconstオブジェクトとして宣言されていますが、メソッドgetCountはconstメソッドではないためcount.getCount()、メンバーを変更する可能性がありますcount

以下のようにコンパイルエラー(私のコンパイラのコアメッセージ):

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

上記の問題を解決するには、次の方法があります。

  1. メソッドuint32_t getCount(){...}をに変更し uint32_t getCount() const {...}ます。したがってcount.getCount()、のメンバーは変更されませんcount

または

  1. に変更uint32_t add(const Count& count){...}uint32_t add(Count& count){...}ます。したがって、countメンバーを変更する必要はありません。

問題については、std :: set内のオブジェクトはconst StudentTとして格納されますが、メソッドgetIdgetNameconstではないため、上記のエラーが発生します。

この質問は、クラスの関数宣言で「const」の意味が最後にあることもわかりますか?詳細については。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.