2011-05-12 84 views
288
#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; 
} 

在行的 '本' 的說法:錯誤:XXX傳遞作爲XXX丟棄預選賽

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

它給出一個錯誤:

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers

../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers

有什麼不對的代碼?謝謝!

+11

代碼片段中的第35行在哪裏? – 2011-05-12 04:54:35

+56

我希望GCC能改善這個錯誤信息,例如「拋棄限定符」 - >「打破常量正確性」 – jfritz42 2013-10-08 22:06:13

+12

@ jfritz42:會拋棄volatile volatile的 – PlasmaHH 2013-12-09 15:40:30

回答

338

std::set中的對象存儲爲const StudentT。因此,當您嘗試使用const對象調用getId()時,編譯器會檢測到問題,即您在const對象上調用非const成員函數,這是不允許的,因爲非const成員函數使NO PROMISE不會修改該對象;所以編譯器會假設getId()可能會嘗試修改該對象,但同時它也會注意到該對象是const的;所以任何修改const對象的嘗試都應該是錯誤的。因此編譯器生成錯誤消息。

解決方法很簡單:讓功能常量爲:

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

這是必要的,因爲現在你可以在const對象調用getId()getName()爲:

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的參考。

+1

這麼明確的解釋。謝謝。 但我想知道你最近的代碼片段。爲什麼在函數參數中使用引用? 'const StudentT&s1,const StudentT&s2'? – 2016-06-12 09:44:11

+0

@RafaelAdel:你使用引用來避免不必要的拷貝,而'const'因爲函數不需要修改對象,所以'const'在編譯時執行。 – Nawaz 2016-06-12 10:41:40

62

不修改類的實例成員函數應該聲明爲const

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

每當你看到「丟棄預選賽」,它在談論constvolatile

+2

@Fred - 您認爲將const修飾符添加到不修改類實例的成員函數是絕對需要的嗎?在這種情況下是否有其他原因導致錯誤?我對此表示懷疑,因爲在我寫的大部分getter中,我不會爲其添加const修飾符。 – Mahesh 2011-05-12 05:01:17

+0

@Fred - http://ideone.com/WXr9z – Mahesh 2011-05-12 05:05:06

+0

@Mahesh:是的,它是[const正確性]的一部分(http://www.parashift.com/c++-faq-lite/const-correctness.html)。我不確定'const'是從哪裏來的,但我懷疑'set'是從迭代器返回一個const引用,以防止實例發生變化,從而使集合失效。 – 2011-05-12 05:05:31

3

其實C++標準(即C++ 0x draft)說(TNX到@Xeo & @Ben福格特指出了這一點給我):

23.2.4 Associative containers
5 For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair. Keys in an associative container are immutable.
6 iterator of an associative container is of the bidirectional iterator category. For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type.

所以VC++ 2008 Dinkumware的實現是錯誤的。


老答案:

你明白我的錯誤,因爲在標準庫的set::iterator的某些實現是一樣的set::const_iterator

例如的libstdC++(隨克++)已經它(參見here整個源代碼):

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

而在SGI的docs它指出:

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編譯你的代碼時不會抱怨你在set::iterator s上調用非const方法。

相關問題