Après de nombreuses investigations avec valgrind, j'ai conclu que std :: vector faisait une copie d'un objet que vous voulez Push_back.
Est-ce vraiment vrai? Un vecteur ne peut pas garder une référence ou le pointeur d'un objet sans copie?!
Merci
Oui, std::vector<T>::Push_back()
crée une copie de l'argument et le stocke dans le vecteur. Si vous souhaitez stocker des pointeurs sur des objets de votre vecteur, créez un fichier std::vector<whatever*>
au lieu de std::vector<whatever>
.
Cependant, vous devez vous assurer que les objets référencés par les pointeurs restent valides tant que le vecteur en contient une référence (les pointeurs intelligents utilisant l'idiome RAII résolvent le problème).
Oui, std::vector
stocke les copies. Comment vector
devrait-il savoir quelle est la durée de vie attendue de vos objets?
Si vous souhaitez transférer ou partager la propriété des objets, utilisez des pointeurs, éventuellement des pointeurs intelligents tels que shared_ptr
(trouvé dans Boost ou TR1 ) pour faciliter la gestion des ressources.
À partir de C++ 11, tous les conteneurs standard (std::vector
, std::map
, etc.) prend en charge la sémantique des déplacements, ce qui signifie que vous pouvez désormais transmettre des valeurs à des conteneurs standard et éviter une copie:
// 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");
Sinon, vous pouvez utiliser divers pointeurs intelligents pour obtenir principalement le même effet:
std::unique_ptr
_ exemple
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
_ exemple
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.
std :: vector fait toujours une copie de tout ce qui est stocké dans le vecteur.
Si vous conservez un vecteur de pointeurs, il en fera une copie, mais pas l'instance sur laquelle il pointe. Si vous utilisez des objets volumineux, vous pouvez (et devriez probablement) toujours utiliser un vecteur de pointeurs. L'utilisation d'un vecteur de pointeurs intelligents d'un type approprié est souvent utile pour des raisons de sécurité, car la gestion de la durée de vie des objets et la gestion de la mémoire peuvent s'avérer délicates.
Non seulement std :: vector crée une copie de tout ce que vous repoussez, mais la définition de la collection indique qu'elle le fera et que vous ne pouvez pas utiliser d'objets sans la sémantique de copie correcte dans un vecteur. Ainsi, par exemple, vous n'utilisez pas auto_ptr dans un vecteur.
La famille emplace
de fonctions membres est pertinente dans C++ 11 et vous permet de transférer la propriété des objets en les déplaçant dans des conteneurs.
Le langage d'usage ressemblerait à
std::vector<Object> objs;
Object l_value_obj { /* initialize */ };
// use object here...
objs.emplace_back(std::move(l_value_obj));
Le déplacement de l'objet lvalue est important car sinon, il serait transmis en tant que référence ou référence constante et le constructeur du déplacement ne serait pas appelé.
Pourquoi at-il fallu beaucoup d’investigations de la part de valgrind pour le découvrir! Prouvez-le vous-même avec un code simple, par exemple.
std::vector<std::string> vec;
{
std::string obj("hello world");
vec.Push_pack(obj);
}
std::cout << vec[0] << std::endl;
Si "hello world" est imprimé, l'objet doit avoir été copié
si vous ne voulez pas les copies; Le meilleur moyen consiste alors à utiliser un vecteur de pointeur (ou une autre structure servant le même objectif). si vous voulez les copies; utilisez directement Push_back (). vous n'avez pas d'autre choix.