2012-01-24 58 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

相关问题