example - vector of vectors c++
¿Está std:: vector copiando los objetos con push_back? (8)
¿Por qué fue necesario investigar mucho para descubrirlo? Pruébelo usted mismo con un código simple, por ejemplo
std::vector<std::string> vec;
{
std::string obj("hello world");
vec.push_pack(obj);
}
std::cout << vec[0] << std::endl;
Si se imprime "hello world", el objeto debe haber sido copiado
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 push_back.
¿Es eso realmente cierto? Un vector no puede mantener una referencia o un puntero de un objeto sin una copia?
Gracias
A partir de C ++ 11, todos los contenedores estándar ( std::vector
, std::map
, etc.) admiten la semántica de movimiento, lo que significa que ahora puede pasar valores a contenedores estándar y evitar una copia:
// Example object class.
class object
{
private:
int m_val1;
std::string m_val2;
public:
// Constructor for object class.
object(int val1, std::string &&val2) :
m_val1(val1),
m_val2(std::move(val2))
{
}
};
std::vector<object> myList;
// #1 Copy into the vector.
object foo1(1, "foo");
myList.push_back(foo1);
// #2 Move into the vector (no copy).
object foo2(1024, "bar");
myList.push_back(std::move(foo2));
// #3 Move temporary into vector (no copy).
myList.push_back(object(453, "baz"));
// #4 Create instance of object directly inside the vector (no copy, no move).
myList.emplace_back(453, "qux");
Alternativamente, puede usar varios punteros inteligentes para obtener el mismo efecto:
std::unique_ptr
example
std::vector<std::unique_ptr<object>> myPtrList;
// #5a unique_ptr can only ever be moved.
auto pFoo = std::make_unique<object>(1, "foo");
myPtrList.push_back(std::move(pFoo));
// #5b unique_ptr can only ever be moved.
myPtrList.push_back(std::make_unique<object>(1, "foo"));
std::shared_ptr
example
std::vector<std::shared_ptr<object>> objectPtrList2;
// #6 shared_ptr can be used to retain a copy of the pointer and update both the vector
// value and the local copy simultaneously.
auto pFooShared = std::make_shared<object>(1, "foo");
objectPtrList2.push_back(pFooShared);
// Pointer to object stored in the vector, but pFooShared is still valid.
Relevante en C ++ 11 es la familia de funciones integradas, que le permiten transferir la propiedad de los objetos moviéndolos a contenedores.
El modismo de uso se vería como
std::vector<Object> objs;
Object l_value_obj { /* initialize */ };
// use object here...
objs.emplace_back(std::move(l_value_obj));
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.
Sí, std::vector<T>::push_back()
crea una copia del argumento y lo almacena en el vector. Si desea almacenar punteros a objetos en su vector, cree un std::vector<whatever*>
lugar de std::vector<whatever>
.
Sin embargo, debe asegurarse de que los objetos a los que hacen referencia los punteros sigan siendo válidos, mientras que el vector contiene una referencia a ellos (los punteros inteligentes que utilizan el modismo RAII resuelven el problema).
Sí, std::vector
almacena copias. ¿Cómo debe saber el vector
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 encuentra en Boost o TR1 ) para facilitar la administración de recursos.
Std :: vector no solo hace una copia de lo que sea que esté retrocediendo, 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.
si no quieres las copias; entonces la mejor manera es usar un vector de puntero (u otra estructura que sirva para el mismo objetivo). si quieres las copias; use directamente push_back (). no tienes otra opción.
std :: vector siempre hace una copia de lo que se almacena 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 está tratando con objetos grandes, puede (y probablemente debería) usar siempre un vector de punteros. A menudo, utilizar un vector de punteros inteligentes de un tipo apropiado es bueno por motivos de seguridad, ya que manejar la vida útil del objeto y la administración de la memoria puede ser complicado.