Después de muchas investigaciones con valgrind, he llegado a la conclusión de que std :: vector hace una copia de un objeto que desea hacer retroceder.
¿Es eso realmente cierto? ¿Un vector no puede mantener una referencia o un puntero de un objeto sin una copia?
Gracias
*
o&
para hacer un puntero o referencia.push_back
: se necesita aconst&
. O arroja el valor (inútil), o hay un método de recuperación. Por lo tanto, observamos la firma deback
y devuelve simple&
, por lo que se copió el valor original oconst
se ha descartado silenciosamente (muy mal: comportamiento potencialmente indefinido). Asumiendo que los diseñadores devector
eran racionales (vector<bool>
no obstante) concluimos que hace copias.Respuestas:
Sí,
std::vector<T>::push_back()
crea una copia del argumento y la almacena en el vector. Si desea almacenar punteros a objetos en su vector, cree un enstd::vector<whatever*>
lugar destd::vector<whatever>
.Sin embargo, debe asegurarse de que los objetos a los que hacen referencia los punteros siguen siendo válidos mientras el vector tiene una referencia a ellos (los punteros inteligentes que utilizan el lenguaje RAII resuelven el problema).
fuente
push_back
realizará un movimiento en lugar de una copia si el argumento es una referencia de valor. (Los objetos se pueden convertir en referencias de valor constd::move()
.)emplace_back
para evitar cualquier copia o movimiento (construir el objeto en el lugar proporcionado por el contenedor).Sí,
std::vector
almacena copias. ¿Cómo debevector
saber cuáles son los tiempos de vida esperados de sus objetos?Si desea transferir o compartir la propiedad de los objetos, use punteros, posiblemente punteros inteligentes como
shared_ptr
(que se encuentran en Boost o TR1 ) para facilitar la administración de recursos.fuente
boost::ptr_vector
?class Foo { typedef boost::shared_ptr<Foo> ptr; };
para escribirFoo::ptr
.shared_ptr
no es exactamente disparar y olvidar. Consulte stackoverflow.com/questions/327573 y stackoverflow.com/questions/701456Desde C ++ 11 en adelante, todos los contenedores estándar (
std::vector
,std::map
, etc) de soporte se mueven semántica, lo que significa que ahora puede pasar a rvalues contenedores estándar y evitar una copia:Alternativamente, puede usar varios punteros inteligentes para obtener el mismo efecto:
std::unique_ptr
ejemplostd::shared_ptr
ejemplofuente
std::make_unique
(molestamente) está disponible solo en C ++ 14 y superior. Asegúrese de decirle a su compilador que establezca su conformidad estándar en consecuencia si desea compilar estos ejemplos.auto pFoo =
para evitar la repetición; y todos losstd::string
moldes se pueden eliminar (hay una conversión implícita de literales de cadena astd::string
)make_unique
se puede implementar fácilmente en C ++ 11, por lo que es solo una ligera molestia para alguien atrapado con un compilador de C ++ 11template<typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>{new T{args...}}; }
std::move()
constd::shared_ptr
, el puntero compartido original podría cambiar su puntero ya que la propiedad se pasó al vector. Ver aquí: coliru.stacked-crooked.com/a/99d4f04f05e5c7f3std :: vector siempre hace una copia de lo que se está almacenando en el vector.
Si mantiene un vector de punteros, hará una copia del puntero, pero no la instancia a la que apunta el puntero. Si se trata de objetos grandes, siempre puede (y probablemente debería) usar un vector de punteros. A menudo, usar un vector de punteros inteligentes de un tipo apropiado es bueno para fines de seguridad, ya que manejar la vida útil de los objetos y la administración de la memoria puede ser complicado de lo contrario.
fuente
Std :: vector no solo hace una copia de lo que está presionando, sino que la definición de la colección establece que lo hará, y que no puede usar objetos sin la semántica de copia correcta dentro de un vector. Entonces, por ejemplo, no usa auto_ptr en un vector.
fuente
Relevante en C ++ 11 es la
emplace
familia de funciones miembro, que le permiten transferir la propiedad de los objetos moviéndolos a contenedores.El modismo de uso se vería así
El movimiento para el objeto lvalue es importante ya que de lo contrario se reenviaría como referencia o referencia constante y no se llamaría al constructor de movimiento.
fuente
si no quieres las copias; entonces la mejor manera es usar un vector puntero (u otra estructura que sirva para el mismo objetivo). si quieres las copias; usar directamente push_back (). No tienes otra opción.
fuente
¿Por qué tomó tanta investigación valgrind para descubrir esto? Solo demuéstralo a ti mismo con un código simple, por ejemplo
Si se imprime "hello world", el objeto debe haberse copiado
fuente