Как правильно повторно использовать перемещенный контейнер?
std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);
// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize
container.push_back(2);
assert(container.size() == 1 && container.front() == 2);
Из того, что я прочитал в стандартном проекте C ++ 0x; ver3 кажется правильным, поскольку объект после перемещения находится в
«Если не указано иное, такие перемещенные объекты должны быть переведены в допустимое, но неуказанное состояние».
Я ни разу не нашел ни одного случая, когда это было бы "иначе указано".
Хотя я нахожу ver3 немного окольным, и я бы предпочел ver1, хотя vec3 может допускать некоторую дополнительную оптимизацию, но, с другой стороны, может легко привести к ошибкам.
Верно ли мое предположение?
c++
c++11
move-semantics
Ронаг
источник
источник
clear
, поскольку он не имеет предварительных условий (и, следовательно, не зависит от состояния объекта).std::vector
реализация, в которой хранился указатель на ее размер (кажется глупым, но законным). Переход от этого вектора может оставить указатель NULL, после чегоclear
произойдет сбой.operator=
также может потерпеть неудачу.Ответы:
Из раздела 17.3.26 спецификации «действительное, но неуказанное состояние»:
Следовательно, объект живой. Вы можете выполнить любую операцию, которая не требует предварительного условия (если вы предварительно не проверите предварительное условие).
clear
, например, не имеет предварительных условий. И он вернет объект в известное состояние. Так что просто очистите его и используйте как обычно.источник
clear
действителен. 2) Пока контейнер находился в неуказанном состоянии, вызовclear
переводит контейнер в заданное состояние, потому что в стандарте предусмотрены постусловия (§23.2.3, таблица 100).std::vector<T>
имеет инвариант класса, которыйpush_back()
всегда действителен (покаT
естьCopyInsertable
).Объект, находящийся в допустимом, но неопределенном состоянии, в основном означает, что, хотя точное состояние объекта не гарантируется, оно является допустимым, и поэтому такие функции-члены (или функции, не являющиеся членами) гарантированно работают, если они не полагаются на объекте, имеющем определенное состояние.
Функция-
clear()
член не имеет предварительных условий для состояния объекта (кроме того, что она действительна, конечно) и поэтому может быть вызвана для перемещенных объектов. С другой стороны, например,front()
зависит от того, что контейнер не пустой, и поэтому его нельзя вызвать, поскольку не гарантируется, что он будет непустым.Следовательно, и ver2, и ver3 должны быть в порядке.
источник
front()
указаны только дляstd::array
, и даже не в таблице.front()
are*a.begin()
, §23.2.1 / 6 говорит: « Если контейнер пуст, тоbegin() == end()
», а §24.2.1 / 5 говорит: « Библиотека никогда не предполагает, что прошлое- конечные значения можно разыменовать. ". Следовательно, я думаю, что предварительные условия для этогоfront()
можно сделать вывод, хотя, безусловно, можно было бы сделать более ясным.Я не думаю, что с перемещенным объектом можно НИЧЕГО сделать (кроме как уничтожить его).
Разве вы не можете использовать
swap
вместо этого, чтобы получить все преимущества перемещения, но оставить контейнер в известном состоянии?источник
std::swap
имеет 2 назначения перемещения, при этом целевые значения этих назначений перемещаются из значений. Для меня это