Подтвердить что ты не робот

Почему std:: set, похоже, заставляет использовать const_iterator?

Рассмотрим простую программу, приведенную ниже, которая пытается выполнить итерацию по значениям набора, используя ссылки NON-const для элементов в нем:

#include <set>
#include <iostream>

class Int
{
public:
   Int(int value) : value_(value) {}
   int value() const { return value_; }
   bool operator<(const Int& other) const { return value_ < other.value(); }
private:
   int value_;
};

int
main(int argc, char** argv) {
   std::set<Int> ints;
   ints.insert(10);
   for (Int& i : ints) {
      std::cout << i.value() << std::endl;
   }
   return 0;
}

При компиляции я получаю сообщение об ошибке gcc:

test.c: In function ‘int main(int, char**)’:
test.c:18:18: error: invalid initialization of reference of type ‘Int&’ from expression of type ‘const Int’  
for (Int& i : ints) {  
              ^  

Да, я знаю, что на самом деле я не пытаюсь изменить элементы в цикле for. Но дело в том, что я должен иметь возможность использовать неконстантную ссылку для использования внутри цикла, поскольку сам набор не является const. Я получаю ту же ошибку, если создаю функцию setter и использую ее в цикле.

4b9b3361

Ответ 1

Набор похож на карту без значений, только клавиши. Поскольку эти ключи используются для дерева, которое ускоряет операции над множеством, они не могут измениться. Таким образом, все элементы должны быть const, чтобы не нарушать ограничения базового дерева.

Ответ 2

std::set использует содержащиеся значения для формирования быстрой структуры данных (обычно это красно-черное дерево). Изменение значения означает, что вся структура должна быть изменена. Таким образом, форсирование const ness, std::set предотвращает нажатие на него в неиспользуемое состояние.

Ответ 3

В ссылке cpp:

В наборе значение элемента также идентифицирует его (значение равно сам ключ, типа T), и каждое значение должно быть уникальным. Значение элементов в наборе нельзя изменить один раз в контейнере ( элементы всегда const), но они могут быть вставлены или удалены из контейнер.

Ответ 4

Поведение по дизайну.

Предоставление вам неконстантного итератора может вдохновить вас на изменение элемента в наборе; последующее итерационное поведение тогда будет undefined.

Обратите внимание, что в стандарте С++ указано, что set<T>::iterator есть const, поэтому старомодный метод pre С++ 11 все равно не будет работать.