РЕДАКТИРОВАТЬ: Этот ответ является неправильным. Добрые комментарии указали на ошибки, но я не удаляю их, потому что на них есть ссылки в других ответах.
@ druckermanly ответил на ваш первый вопрос, в котором говорилось, что изменение ключей в map
force нарушает порядок, на котором строится внутренняя структура данных map
(красно-черное дерево). Но безопасно использовать метод extract
, потому что он делает две вещи: вынимает ключ из карты и затем удаляет его, чтобы он вообще не влиял на упорядоченность карты.
Другой заданный вами вопрос о том, не вызовет ли это проблемы при деконструкции, не является проблемой. Когда карта деконструирует, она вызывает деконструктор каждого из своих элементов (mapped_types et c.), А метод move
гарантирует, что безопасно деконструировать класс после его перемещения. Так что не волнуйся. В двух словах, именно операция move
гарантирует, что можно безопасно удалить или переназначить какое-то новое значение для «перемещенного» класса. В частности, для string
метод move
может установить свой указатель на символ nullptr
, поэтому он не удаляет фактические данные, которые были перемещены при вызове деконструктора исходного класса.
Комментарий напомнил мне о точке, которую я упустил, в основном он был прав, но есть одна вещь, с которой я не полностью согласен: const_cast
, вероятно, не UB. const
- это просто обещание между компилятором и нами. объекты, отмеченные как const
, по-прежнему являются объектами, такими же, как объекты, не обозначенные const
, с точки зрения их типов и представлений в двоичной форме. Когда const
отбрасывается, он должен вести себя так, как будто это обычный изменяемый класс. Что касается move
, если вы хотите его использовать, вы должны передать &
вместо const &
, так как я вижу, что это не UB, он просто нарушает обещание const
и перемещается нет данных.
Я также провел два эксперимента, используя MSV C 14.24.28314 и Clang 9.0.0 соответственно, и они дали тот же результат.
map<string, int> m;
m.insert({ "test", 2 });
m.insert({ "this should be behind the 'test' string.", 3 });
m.insert({ "and this should be in front of the 'test' string.", 1 });
string let_me_USE_IT = std::move(const_cast<string&>(m.find("test")->first));
cout << let_me_USE_IT << '\n';
for (auto const& i : m) {
cout << i.first << ' ' << i.second << '\n';
}
output:
test
and this should be in front of the 'test' string. 1
2
this should be behind the 'test' string. 3
Мы можем видеть, что строка '2' теперь пуста, но, очевидно, мы нарушили упорядоченность карты, потому что пустая строка должна быть перемещена вперед. Если мы попытаемся вставить, найти или удалить некоторые определенные c узлы карты, это может привести к катастрофе.
В любом случае, мы можем согласиться с тем, что манипулировать внутренними данными любые классы в обход их интерфейсов publi c. Функции find
, insert
, remove
и т. Д. Полагаются на правильность внутренней структуры данных, и именно поэтому мы должны избегать мысли заглянуть внутрь.