12
votes

Comment les conteneurs STL copient-ils des objets?

Je connais des conteneurs STL comme vecteur code> copie l'objet quand il est ajouté. Push_back CODE> La méthode ressemble à:

struct Foo
{
    Foo()
    {
        std::cout << "Inside Foo constructor" << std::endl;
    }

    Foo(const Foo& f)
    {
        std::cout << "inside copy constructor" << std::endl;
    }
};

Foo f;
std::vector<Foo> foos;
foos.push_back(f);


0 commentaires

3 Réponses :


13
votes

Il utilise probablement "Placement Nouveau " pour construire l'objet dans sa matrice interne. Placement Nouveau n'alloue pas de mémoire; Cela place simplement l'objet où vous spécifiez et appelle le constructeur. La syntaxe est nouvelle (adresse) (constructor_arguments) .

Le constructeur de copie T :: t (t const &) est appelé pour créer la copie en place . Quelque chose comme ça (simplifié): xxx

note que t doit avoir un constructeur de copie pour que cela fonctionne. Par défaut (si vous ne faites rien), il en reçoit un gratuitement. Si vous le définissez explicitement, il doit être public pour vecteur pour fonctionner.

Voici comment Gnu's LibstDC ++ fait-il , mais je doute que ce sera très éclairant. Il y a un allocator (le deuxième argument de modèle à vecteur ) qui le rend moins simple.


6 commentaires

Ceci est correct quand T a un constructeur sans paramètre. Mais que se passera-t-il quand il a un constructeur paramétré? Comment vecteur peut-il initialiser un nouvel objet?


C'est bon quand T a un Copy Constructor . Ce qui est fait, par défaut, et si vous le mettez en train de le mettre en œuvre, sauf si vous avez explicitement fait privé ou protégé .


Merci. Je vais enquêter plus loin.


Votre explication est claire. Je me demande pourquoi ils n'ont pas de signature comme push_back (t const article) et en évitant le placement nouveau.


Cela ferait une copie de l'élément lorsqu'elle sera transmise à la fonction (car elle est transmise), que la version pass par référence évite. Il pourrait éviter le placement nouveau à l'aide de l'opérateur = , mais cela nécessiterait qu'il existe déjà un objet initialisé à cet endroit (pour appeler opérateur = ON) et nécessite donc t pour avoir un constructeur par défaut.


L'autre avantage d'utiliser le placement nouveau est que l'espace inutilisé que le vecteur a alloué, mais qui n'a pas encore été rempli, ne doit pas être initialisé du tout. Il s'agit d'une petite optimisation si le constructeur par défaut de T existe et ne fait pas grand chose, mais une différence significative si le constructeur par défaut de T fait beaucoup de travail, ou a des effets secondaires. Et comme le souligne Thomas, il permet de ne pas avoir de constructeur de no-args du tout.



1
votes

Il utilise le placement nouvel opérateur et la copie-latrose-le construit en mémoire unitalisé;

Le placement nouveau crée un nouvel élément à une adresse spécifiée en mémoire, dans le boîtier de vecteur, l'extrémité actuelle (); xxx

regarder http://spotep.com/dev/devector .h qui a un code assez clair (par opposition à la plupart des implémentations stl).


0 commentaires

3
votes

Le SDK C ++ prend toujours const t & comme paramètre de fonction pour l'efficacité.

Dans votre cas si elle prend t comme paramètre, l'action de copie sera effectuée deux fois, une pour la transmettre à la fonction push_back (f) , un pour l'ajout interne au conteneur. Et en prenant const t & comme paramètre, une seule copie n'est nécessaire!


0 commentaires