Запуск с 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 точки.
Циклы для цикла по набору и наборам температура. Логически это позволяется, так как температура не используется в операторах сравнения.
Этот код компилирует правильно в Visual Studio 2005, но дает ошибки компиляции в Visual Studio 2010 на следующей строке (в для цикла):
DataPoint &point = *it;
Данная ошибка состоит в том, что это не может присвоить "константе DataPoint" [неконстанта] "DataPoint и".
Кажется, что Вы имеете не достойный (= негрязный) способ написать этот код в VS2010, если у Вас есть оператор сравнения, который только сравнивает части элементов данных.
Возможные решения:
Но мне оба решения кажутся довольно 'грязными'.
Похоже, что комитет по стандартам C++ пропустил эту ситуацию. Или нет?
Что чистые решения состоят в том, чтобы решить эту проблему? Некоторые из Вас встречались с этой той же проблемой и как Вы решали ее?
Patrick
Итератор должен давать вам константную ссылку (и это то, что в Стандарте сказано, что он должен do), потому что изменение упомянутой вещи нарушит действительность базовой структуры данных набора - набор не «знает», что поле, которое вы изменяете, на самом деле не является частью ключа. Альтернативой является внесение изменений путем удаления и повторного добавления или использование вместо этого std :: map.
Если вы не хотите удалять и добавлять заново, как предлагает Нил, вы можете сделать setTemperature
const
и m_temperature
mutable
.
Set должен возвращать итератор const, потому что он не знает, могут ли функции-члены изменить упорядочение.
Похоже, что вам действительно нужна карта, где вы сопоставляете неизменяемый ключ (x, y) с переменной температурой.