Domanda Std :: vector copia gli oggetti con un push_back?


Dopo molte indagini con valgrind, ho concluso che std :: vector fa una copia di un oggetto che vuoi push_back.

È proprio vero? Un vettore non può mantenere un riferimento o un puntatore di un oggetto senza una copia?!

Grazie


128
2018-02-16 17:54


origine


risposte:


Sì, std::vector<T>::push_back() crea una copia dell'argomento e lo memorizza nel vettore. Se vuoi memorizzare puntatori su oggetti nel tuo vettore, crea a std::vector<whatever*> invece di std::vector<whatever>.

Tuttavia, è necessario assicurarsi che gli oggetti referenziati dai puntatori rimangano validi mentre il vettore contiene un riferimento a essi (i puntatori intelligenti che utilizzano l'idioma RAII risolvono il problema).


139
2018-02-16 17:57



Sì, std::vector memorizza copie. Come dovrebbe vector sai quali sono i tempi di vita attesi dei tuoi oggetti?

Se si desidera trasferire o condividere la proprietà degli oggetti, utilizzare i puntatori, possibilmente puntatori intelligenti come shared_ptr (trovato in Incremento o TR1) per facilitare la gestione delle risorse.


33
2018-02-16 17:56



Da C ++ 11 in poi, tutti i contenitori standard (std::vector, std::map, ecc) supportano la semantica del movimento, il che significa che ora puoi passare rvalues ​​ai contenitori standard ed evitare 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");

In alternativa puoi usare vari puntatori intelligenti per ottenere lo stesso effetto:

std::unique_ptr esempio

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 esempio

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.

16
2017-11-01 10:45



std :: vector fa sempre una copia di ciò che viene memorizzato nel vettore.

Se stai mantenendo un vettore di puntatori, allora farà una copia del puntatore, ma non l'istanza a cui punta il puntatore. Se hai a che fare con oggetti di grandi dimensioni, puoi (e probabilmente dovrebbe) usare sempre un vettore di puntatori. Spesso, l'utilizzo di un vettore di puntatori intelligenti di un tipo appropriato è utile per motivi di sicurezza, dal momento che gestire la durata degli oggetti e la gestione della memoria può essere complicato altrimenti.


14
2018-02-16 17:57



Std :: vector non solo fa una copia di ciò che stai respingendo, ma la definizione della collezione afferma che lo farà, e che non puoi usare oggetti senza la semantica della copia corretta all'interno di un vettore. Quindi, per esempio, non usi auto_ptr in un vettore.


3
2018-02-16 18:01



Rilevante in C ++ 11 è il emplace famiglia di funzioni membro, che consentono di trasferire la proprietà degli oggetti spostandoli in contenitori.

L'idioma di utilizzo sarebbe simile

std::vector<Object> objs;

Object l_value_obj { /* initialize */ };
// use object here...

objs.emplace_back(std::move(l_value_obj));

Lo spostamento per l'oggetto lvalue è importante in quanto altrimenti sarebbe inoltrato come riferimento o riferimento const e il costruttore di movimento non verrebbe chiamato.


2
2017-07-18 16:15



se non vuoi le copie; allora il modo migliore è usare un vettore puntatore (o un'altra struttura che serve per lo stesso obiettivo). se vuoi le copie; utilizzare direttamente push_back (). non hai altra scelta.


0
2018-02-16 18:02



Perché è bastato un sacco di approfondite indagini per scoprirlo! Provalo solo con un semplice codice, ad es.

std::vector<std::string> vec;

{
      std::string obj("hello world");
      vec.push_pack(obj);
}

std::cout << vec[0] << std::endl;  

Se viene stampato "Hello World", l'oggetto deve essere stato copiato


0
2018-02-07 11:45