Уб в общем случае
Интересно, что изменилось с Scott Meyers - Effective STL, p79: As an example, look again at the setTitle call we just saw that failed to compile under some implementations: EmplDSet::iterator i = se.find(selectedlD); if (i != se.end()) { i->setTitle("Corporate Deity"); // some STL implementations will reject this line because *i is const } To get this to compile and behave correctly, we must cast away the constness of *i. Here's the correct way to do it: if (i != se.end()) { const_cast<Employee&>(*i).setTitle("Corporate Deity"); // cast away constness of*i }
Effective STL уже устарело, ну и в те древние времена культура разработки была хуже
Он ещё make_unique предлагал самому в std добавить, хотя формально это уб.
Рекомендую дочитать главу до конца, вместо того чтобы вырывать слова из контекста.
Там сказано, что это UB? Нет. Там дальше просто приведён универсальный алгоритм.
У меня есть сомнения, что там речь шла о добавлении в namespace std, скорее всего о добавлении в свой неймспейс.
int i = 0; const int& cr = i; const_cast<int&>(cr) = 42; В этом коде нет UB, но компилятор не подскажет когда оно появится.
Это же пример плохого кода, который сам автор не рекомендует. В начале главы он обозначает проблему и показывает плохое решение, объясняет его недостатки и в конце предлагает нормальное решение. Такой подход гораздо полезней во время обучения, так как студенту не нужно самостоятельно наступать на эти грабли, а достаточно дочитать главу до конца.
Никто и не говорит, что это лучшие практики. Это способ решения поставленной задачи как есть. Понятно, что использовать extract или перейти на map это более правильный подход.
Extract не может быть правильным подходом. Это erase/insert с поиском и перебалансировкой. Если очень надо лучше уж на intrusive тогда перейти. Или set из указателей если это просто индекс.
Это подход, предлагаемый Мейерсом в упомянутой книге как универсальный. Асимптотика, если тебе надо было этот элемент искать, не изменяется.
Extract это потенциально перебалансировка. Последующая вставка это logn + опять потенциально перебалансировка. Вообще избыточна эта const'овость итераторов на мой взгляд. Всё равно есть много способов отстрелить ногу :) нетранзитивный компаратор, mutable, сравнение через указатели...
Мне тоже иногда хочется mutable set, но я не готов видеть его в проде.
Тут же вопрос обычно в разделении на пару ключ/значение там где оно не надо. Если ключ маленький, просто делаем мап и дублируем ключ. А если что сложнее... Да тоже вариантов много, но все с разными лишними телодвижениями. Иногда даже const_cast норм :)
Да, я понимаю проблему, но мне кажется лучше иметь безопасное решение по-умолчанию. Все-таки foot gun'ы связанные с компаратором сразу вызовут вопросы на ревью и ломают не только set. А здесь еще одно место за которым нужно следить. При этом на ревью изначальной реализации это будет еще можно проконтролировать. А вот при последущей модификации кода пропустить проблему будет легко.
О, надо по аналогии с transparent втащить мутабельность set через компаратор!
А что за transparent?
Компаратор может содержать нечто под названием is_transparent, что врубает полиморфный поиск. Т.е. поиск с использованием ключей не const key_type&
Точно так же можно туда засандалить is_partial detection. Чтобы const снять с итераторов.
std::less<void> как пример transparent
хм. Спасибо. Надо будет еще раз посмотреть как это работает.
Что-то в этом есть.
Это очччень полезная штука, например поиск по string_view когда ключ string и т.п. Я их вообще затайпдефил сразу, transparent_map/transparent_set.
это гораздо сложнее, чем на ровном месте инты поменять в std::set<int>
Это ровно то же самое, просто за вычетом allocate/deallocate.
Ну условно erase это extract + drop node. Insert это create node/find insert point/insert/rebalance. Убираются только drop/create node.
А, я про неконстантный итератор имел ввиду
Ну я ж говорю, согласен, пусть будет const, шикарный вариант это протащить условно мутабельность через трейты компаратора.
Обсуждают сегодня