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

Что происходит, когда вы изменяете элемент std:: set?

Если я изменяю элемент std:: set, например, через итератор, я знаю, что он не "повторно вставлен" или "прибегает", но есть ли упоминание о том, вызывает ли он поведение undefined? Например, я бы предположил, что вставки будут испорчены. Есть ли какие-либо упоминания о том, что происходит?

4b9b3361

Ответ 1

Вы не должны редактировать значения, хранящиеся в наборе напрямую. Я скопировал это из документации MSDN, которая несколько авторитетна:

Используется набор классов контейнеров STL для хранения и извлечения данных из коллекции, в которой значения содержащихся элементов являются уникальными и служат ключевыми значениями согласно к которой данные автоматически приказал. Значение элемента в набор не может быть изменен напрямую. Вместо этого вы должны удалить старые значения и вставьте элементы с новыми значениями.

Почему это довольно легко понять. Реализация set не будет знать, что вы изменили значение за его спиной. Обычная реализация - красно-черное дерево. Изменив значение, позиция в дереве для этого экземпляра будет неправильной. Вы ожидаете увидеть все неправильное поведение, например, exists запросы, возвращающие неверный результат, в связи с тем, что поиск идет по неправильной ветки дерева.

Ответ 2

Точный ответ зависит от платформы, но, как правило, "ключ" (материал, который вы помещаете в набор или первый тип карты), должен быть "неизменным". Проще говоря, это не должно быть изменено, и нет такой вещи, как автоматическая повторная установка.

Точнее, переменные-члены, используемые для сравнения ключа, не должны быть изменены.

Компилятор Windows vc довольно гибкий (протестирован с VC8), и этот код компилируется:

// creation
std::set<int> toto;
toto.insert(4);
toto.insert(40);
toto.insert(25);

// bad modif
(*toto.begin())=100;

// output
for(std::set<int>::iterator it = toto.begin(); it != toto.end(); ++it)
{
    std::cout<<*it<<" ";
}
std::cout<<std::endl;

Выход 100 25 40, который, очевидно, не отсортирован... Плохо... Тем не менее, такое поведение полезно, когда вы хотите изменить данные, не участвующие в операторе <. Но вам лучше знать, что вы делаете: цена, которую вы получаете за слишком гибкую.

Некоторые могут предпочесть поведение gcc (проверено с помощью 3.4.4), которое дает ошибку "назначение места только для чтения". Вы можете обойти это с помощью const_cast:

const_cast<int&>(*toto.begin())=100;

Что теперь компилируется на gcc, тот же вывод: 100 25 40. Но, по крайней мере, это, вероятно, заставит вас задаться вопросом, что происходит, затем перейдите в переполнение стека и посмотрите этот поток: -)

Ответ 3

Вы не можете этого сделать; они const. Существует не метод, с помощью которого set может обнаружить, что вы вносите изменения во внутренний элемент, и в результате вы не можете этого сделать. Вместо этого вам нужно удалить и повторно вставить элемент. Если вы используете элементы, которые дорого копировать, вам, возможно, придется переключиться на использование указателей и пользовательских компараторов (или переключиться на компилятор С++ 1x, который поддерживает ссылки rvalue, что сделает вещи намного приятнее).