Я только проанализировал версию GCC.Вот что происходит: код обрабатывает различные типы распределителей.Если у распределителя есть черта _S_propagate_on_move_assign
или _S_always_equal
, то движение почти бесплатное, как вы ожидаете.Это if
в ходу operator=
:
if (!__str._M_is_local()
&& (_Alloc_traits::_S_propagate_on_move_assign()
|| _Alloc_traits::_S_always_equal()))
// cheap move
else assign(__str);
Если условие истинно (_M_is_local()
означает небольшую строку, описание здесь ), то ход будет дешевым.
Если оно ложно, то оно вызывает normal assign
(не движущийся).Это тот случай, когда либо:
- строка мала, поэтому
assign
сделает простой memcpy (дешевый) - , либо у распределителя нет черты всегда равно или распространять-на-ходу-назначать , поэтому назначение будет выделять (недешево)
Что этозначит?
Это означает, что если вы используете распределитель по умолчанию (или любой распределитель с чертами, упомянутыми ранее), то ход все еще почти свободен .
НаС другой стороны, сгенерированный код неоправданно огромен и, я думаю, его можно улучшить.Он должен иметь отдельный код для обработки обычных распределителей или иметь лучший код assign
(проблема в том, что assign
не проверяет _M_is_local()
, но выполняет проверку емкости, поэтому компилятор не может решить,Выделение необходимо или нет, поэтому он вставляет кодовый путь выделения в исполняемый файл без необходимости - вы можете проверить точные детали в исходном коде).