Const ссылки при разыменовании итератора на множестве, начиная с Visual Studio 2010 - PullRequest
11 голосов
/ 26 марта 2010

Начиная с Visual Studio 2010, итерация по набору, похоже, возвращает итератор, который разыменовывает данные как «постоянные данные» вместо неконстантных.

Следующий код является примером того, что компилируетсяв 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, но выдает ошибки компиляции в Visual Studio 2010 в следующей строке (в цикле for):

   DataPoint &point = *it;

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

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

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

  • Добавление const-передача на строку, где она выдает ошибку
  • Создание изменяемой температуры и установка setTempera по постоянному методу

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

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

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

Патрик

Ответы [ 4 ]

13 голосов
/ 26 марта 2010

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

1 голос
/ 22 сентября 2010

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

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

Dennis

0 голосов
/ 29 марта 2010

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

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

0 голосов
/ 26 марта 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...