¿Cuál es la forma correcta de reutilizar un contenedor movido?
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);
Por lo que he leído en el borrador estándar C ++ 0x; ver3 parece ser la forma correcta, ya que un objeto después del movimiento está en un
"A menos que se especifique lo contrario, dichos objetos de origen se colocarán en un estado válido pero no especificado".
Nunca he encontrado ninguna instancia donde esté "especificado de otra manera".
Aunque encuentro ver3 un poco indirecto y preferiría ver1 mucho, aunque vec3 puede permitir alguna optimización adicional, pero por otro lado puede conducir fácilmente a errores.
¿Es correcta mi suposición?
c++
c++11
move-semantics
ronag
fuente
fuente
clear
, ya que no tiene condiciones previas (y, por lo tanto, no depende del estado del objeto).std::vector
implementación que almacenó un puntero a su tamaño (parece tonto, pero legal). Moverse desde ese vector podría dejar el puntero NULL, después de lo cualclear
fallaría.operator=
también podría fallar.Respuestas:
De la sección 17.3.26 de la especificación "estado válido pero no especificado":
Por tanto, el objeto está vivo. Puede realizar cualquier operación que no requiera una condición previa (a menos que primero verifique la condición previa).
clear
, por ejemplo, no tiene condiciones previas. Y devolverá el objeto a un estado conocido. Así que límpialo y úsalo normalmente.fuente
clear
es válida. 2) Mientras el contenedor estaba en un estado no especificado, la llamadaclear
pone al contenedor en un estado específico porque tiene postcondiciones obligatorias en la norma (§23.2.3 tabla 100).std::vector<T>
tiene una clase invariante quepush_back()
siempre es válida (siempre que loT
seaCopyInsertable
).El hecho de que el objeto esté en un estado válido, pero no definido, básicamente significa que, si bien el estado exacto del objeto no está garantizado, es válido y, como tales funciones miembro (o funciones no miembro) están garantizadas para funcionar siempre y cuando no dependan en el objeto que tiene un cierto estado.
La
clear()
función miembro no tiene condiciones previas sobre el estado del objeto (aparte de que es válida, por supuesto) y, por lo tanto, puede invocarse en objetos movidos desde. Por otro lado, por ejemplo,front()
depende de que el contenedor no esté vacío y, por lo tanto, no se puede llamar, ya que no se garantiza que no esté vacío.Por lo tanto, tanto ver2 como ver3 deberían estar bien.
fuente
front()
se indican solo parastd::array
, e incluso no en la tabla.front()
are*a.begin()
, §23.2.1 / 6 dice " Si el contenedor está vacío, entoncesbegin() == end()
", y §24.2.1 / 5 dice " La biblioteca nunca asume que el pasado- los valores finales son desreferenciables. ". En consecuencia, creo quefront()
se pueden inferir las condiciones previas para , aunque ciertamente podría aclararse más.No creo que puedas hacer NADA con un objeto movido (excepto destruirlo).
¿No se puede usar
swap
en su lugar, para obtener todas las ventajas de mudarse pero dejar el contenedor en un estado conocido?fuente
std::swap
tiene 2 asignaciones de movimiento, y los objetivos de esas asignaciones son valores de movimiento. Eso cuenta como "hacer algo con un objeto movido" para mí