Недавно я понял, что добавление семантики перемещения в С++ 11 (или, по крайней мере, моя реализация этого, Visual С++) активно (и довольно резко) нарушило одну из моих оптимизаций.
Рассмотрим следующий код:
#include <vector>
int main()
{
typedef std::vector<std::vector<int> > LookupTable;
LookupTable values(100); // make a new table
values[0].push_back(1); // populate some entries
// Now clear the table but keep its buffers allocated for later use
values = LookupTable(values.size());
return values[0].capacity();
}
Я следил за этим типом шаблона для повторного использования контейнеров: я бы повторно использовал один и тот же контейнер вместо того, чтобы уничтожать и воссоздавать его, чтобы избежать ненужного перераспределения кучи и (немедленного) перераспределения.
В С++ 03 это сработало нормально - это означает, что этот код использовался для возврата 1
, потому что векторы были скопированы по-разному, а их базовые буферы были сохранены как есть. Следовательно, я мог бы модифицировать каждый внутренний вектор, зная, что он может использовать тот же буфер, что и раньше.
В С++ 11, однако, я заметил, что это приводит к перемещению правой части в левую сторону, которая выполняет элементное перемещение-присваивание каждому вектору с левой стороны, Это, в свою очередь, приводит к тому, что вектор отбрасывает свой старый буфер, внезапно уменьшая его емкость до нуля. Следовательно, мое приложение теперь значительно замедляется из-за избыточного распределения/освобождения кучи.
Мой вопрос: это поведение является ошибкой, или это намеренно? Он даже определен стандартом вообще?
Обновление:
Я только понял, что правильность этого конкретного поведения может зависеть от того, может ли a = A()
аннулировать итераторы, указывающие на элементы a
. Тем не менее, я не знаю, каковы правила аннулирования итератора для назначения переадресации, поэтому, если вы знаете о них, возможно, стоит упомянуть их в вашем ответе.