从Visual Studio 2010开始,在集合上取消引用迭代器时的Const引用

时间:2010-03-26 12:19:45

标签: c++ visual-studio-2010 iterator c++11

从Visual Studio 2010开始,迭代一个集合似乎返回一个迭代器,它将数据解引用为'const data'而不是non-const。

以下代码是在Visual Studio 2005上进行编译但在2010年没有编译的示例(这是一个人为的示例,但清楚地说明了我们在自己的代码中找到的问题)。

在这个例子中,我有一个存储位置和温度的类。我定义了比较运算符(不是全部,只是足以说明问题),只使用位置,而不是温度。关键是,如果位置相同,对我来说两个实例是相同的;我不关心温度。

#include <set>

class DataPoint
   {
   public:
      DataPoint (int x, int y) : m_x(x), m_y(y), m_temperature(0) {}
      void setTemperature(double t) {m_temperature = t;}
      bool operator<(const DataPoint& rhs) const
         {
         if (m_x==rhs.m_x) return m_y<rhs.m_y;
         else              return m_x<rhs.m_x;
         }
      bool operator==(const DataPoint& rhs) const
         {
         if (m_x!=rhs.m_x) return false;
         if (m_y!=rhs.m_y) return false;
         return true;
         }
   private:
      int m_x;
      int m_y;
      double m_temperature;
   };

typedef std::set<DataPoint> DataPointCollection;

void main(void)
{
DataPointCollection points;

points.insert (DataPoint(1,1));
points.insert (DataPoint(1,1));
points.insert (DataPoint(1,2));
points.insert (DataPoint(1,3));
points.insert (DataPoint(1,1));

for (DataPointCollection::iterator it=points.begin();it!=points.end();++it)
   {
   DataPoint &point = *it;
   point.setTemperature(10);
   }
}

在主程序中,我有一个集合,我添加了一些点。为了检查比较运算符的正确性,我多次添加具有相同位置的数据点。在写集合的内容时,我可以清楚地看到集合中只有3个点。

for循环遍历集合,并设置温度。从逻辑上讲,这是允许的,因为比较运算符中没有使用温度。

此代码在Visual Studio 2005中正确编译,但在以下行(在for循环中)中提供Visual Studio 2010中的编译错误:

   DataPoint &point = *it;

给出的错误是它不能将“const DataPoint”分配给[non-const]“DataPoint&amp;”。

如果您的比较运算符仅比较部分数据成员,那么您似乎没有在VS2010中编写此代码的方式(=非脏)。

可能的解决方案是:

  • 将const-cast添加到出错的行
  • 使温度可变并使setTemperature成为const方法

但对我而言,这两种解决方案似乎都很“脏”。

看起来C ++标准委员会忽略了这种情况。或者不是?

解决此问题的清洁解决方案是什么? 你们有些人遇到同样的问题,你们是如何解决的?

帕特里克

4 个答案:

答案 0 :(得分:13)

迭代器应该给你一个const引用(这就是标准所说它应该做的),因为更改引用的东西会破坏集合的底层数据结构的有效性 - 集合不会“知道”你正在改变的领域实际上并不是关键的一部分。替代方法是通过删除和重新添加来进行更改,或者改为使用std :: map。

答案 1 :(得分:1)

刚刚开始转换到2010年,这是我们面临的最大障碍。幸运的是,他们确实揭示了一些长期存在的问题,我们正在改变构成集合排序的部分内容。

在其他情况下,我们的解决方案是使用mutable和declare方法作为const。当通过引用(指针或引用)将解除引用的迭代器传递给函数时,如果没有更改,我们使参数变为consst。

丹尼斯

答案 2 :(得分:0)

如果你不想删除和重新添加Neil建议你可以setTemperature constm_temperature mutable

答案 3 :(得分:0)

Set应该返回一个const迭代器,因为它不知道任何成员函数是否可以改变排序。

看起来你真的想要一张地图,你可以将不可变(x,y)键映射到可变温度。