Константы при разыменовании итератора на множестве, начиная с Visual Studio 2010

Начиная с Visual Studio 2010, итерация по набору, похоже, возвращает итератор, который разыскивает данные как "данные const" вместо не 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-loop над множеством и задают температуру. Логически это допускается, так как температура не используется в операторах сравнения.

Этот код правильно компилируется в Visual Studio 2005, но дает ошибки компиляции в Visual Studio 2010 в следующей строке (в цикле for):

   DataPoint &point = *it;

Приведенная ошибка заключается в том, что он не может назначить "const DataPoint" для [не const] "DataPoint &".

Кажется, что у вас нет достойного (= не грязного) способа записи этого кода в VS2010, если у вас есть оператор сравнения, который сравнивает только части элементов данных.

Возможные решения:

  • Добавление const-cast в строку, где она дает ошибку
  • Изменение температуры и создание setTemperature - метод const

Но для меня оба решения кажутся довольно "грязными".

Похоже, что комитет по стандартам С++ упустил эту ситуацию. Или нет?

Каковы чистые решения для решения этой проблемы? Некоторые из вас столкнулись с этой проблемой и как вы ее разрешили?

Патрик

Ответ 1

Итератор должен предоставить вам ссылку на константу (и то, что Стандарт говорит, что она должна делать), потому что изменение упомянутой вещи приведет к уничтожению действительности установленной базовой структуры данных - набор не "знает", что поле, которое вы меняете, на самом деле не является частью ключа. Альтернативы должны вносить изменения путем удаления и повторного добавления или вместо использования std:: map.

Ответ 2

Совсем недавно началось наше преобразование в 2010 году, и это было самым большим препятствием, с которым мы столкнулись. К счастью, они обнаружили некоторые давние проблемы, когда мы меняли часть того, что составляло заказ набора.

В других случаях наше решение заключалось в использовании методов mutable и declare как const. При передаче разыменованного итератора на функцию по ссылке (либо указатель, либо ссылку) мы сделали аргумент consst, если он не был изменен.

Dennis

Ответ 3

Если вы не хотите удалять и повторно добавлять, поскольку Neil предлагает сделать setTemperature const и m_temperature mutable.

Ответ 4

Предполагается, что Set должен возвращать константный итератор, потому что он не знает, могут ли какие-либо функции-члены изменять порядок.

Кажется, что вам действительно нужна карта, где вы указываете свою неизменяемую (x, y) клавишу на переменную температуру.