2012-01-24 57 views
2

存在類A,其中包含兩個重載的方法getItems();C++,返回const和非const引用std :: set項

typedef std::vector <int> TItems; 

template <typename T> 
class A 
{ 
private: 
    T a; 
    TItems items; 

public: 
    A(){} 
    A (const T a_, const TItems & items_) : a(a_) , items (items_) {} 
    bool operator() (const A <T> &aa) {return a < aa.a;} 
    TItems const & getItems() const {return items} 
    TItems & getItems() {return items} 
}; 

和集合A的對象

template <typename T> 
struct TSet {typedef std::set <A <T> > Type;}; 

我想返回const引用/參考TItems,但只有第二個方法效果

int main() 
{ 
TSet <double> ::Type t; 
TSet <double> ::Type::iterator it = t.begin(); 
t.insert (A <double>(5, TItems(10,10))); 

const TItems *items = &(it->getItems()); //OK 
TItems *items = &(it->getItems()); //Error 
} 

Error 1 error C2440: 'initializing' : cannot convert from 'const TItems *' to 'TItems * 

是它的原因,非常量引用使得能夠修改導致潛在重排的A對象。但是集合的項目不是由A.items排列,而是由a排列。

有沒有辦法使用非常量引用來修改A.items?

回答

2

是否因爲非常量引用能夠修改A對象而導致潛在的重新排列?

沒錯。 std::set的元素(和BTW std::map的鍵)是不可變的,結構只會給你const限定的元素。所以,你可以選擇

  • 改變你的結構std::map,把你的a關鍵和items數據
  • ,如果你有絕對的把握,你將不會被操縱與items打破訂貨後,可以const_cast(或者如果適合您,則聲明itemsmutable)。
+0

技術上'const_cast'是UB爲此目的(即使我有罪使用它的情況下,我保證自己的順序),並且'mutable'不會在這裏改變任何東西。不,沒有出路:如果你允許用戶有可能違反命令,你不應該首先使用'set'。 –

+0

@AlexandreC。請注意詳細說明爲什麼未定義的行爲應該發生,如果您從集合元素中刪除const並且只更改那些不用於排序的成員?例如,您可以將用於排序的成員聲明爲const。這並不意味着整個set元素必須是const。 – Kenji

1

如果允許更改集合元素,則可能會破壞實現集合的結構(例如平衡搜索樹)的不變量。集合的元素因此必須是不可變的。所以如果你想修改一個元素,你必須刪除一個元素並用新元素替換它。特別是,你不能指望一個非const引用通過迭代器到set(如果你可以修改它,你可能會破壞排序)。 。

0

您不能更改存儲在std :: set中的對象,因爲這會破壞set不變量。相反,您可以從設置中刪除對象,然後修改並再次插入。

另一種可能性是使用std :: map代替。地圖的關鍵點不能修改,但值可以。

+0

好的,但如何修改它,如果該集合給我一個常量迭代器.. – Nuclear

+0

如果你引用第一個選項,那麼你可以創建一個副本,從集合中刪除它,修改該副本並將其插入到集合中。 – frast

相關問題