2009-06-17 11 views
3

Je me demandais pourquoi les modèles vectoriels effectuent deux allocations, alors qu'une seule semble être nécessaire.Allocations vectorielles STL

Par exemple ceci:

#include <vector> 
#include <iostream> 

class A { 
    public: 
     A(const A &a) { 
      std::cout << "Calling copy constructor " << this << " " << &a << "\n"; 
     } 
     A() { 
      std::cout << "Calling default constructor " << this << "\n"; 
     } 
     ~A() { 
      std::cout << "Calling destructor " << this << "\n"; 
     } 
}; 

int main(int argc, char **argv) 
{ 
    std::vector <A> Avec; 

    std::cout << "resize start\n"; 
    Avec.resize(1); 
    std::cout << "resize end\n"; 

    return 0; 
} 

Sorties:

 
resize start 
Calling default constructor 0x7fff9a34191f 
Calling copy constructor 0x1569010 0x7fff9a34191f 
Calling destructor 0x7fff9a34191f 
resize end 

Répondre

15

Il ne fonctionne pas deux allocations, il crée un objet par le constructeur par défaut pour passer dans Redimensionner, puis copier cet objet dans la nouvelle position, puis détruire l'argument.

Si vous regardez les arguments pour redimensionner:

void resize(n, t = T()) 

Il a comme argument en défaut un objet construit par défaut de type T (ce qui est le constructeur par défaut étant appelé dans la sortie). Ensuite, dans la fonction, il copie ceci dans la bonne position (c'est le constructeur de la copie). Après la fin de la fonction de redimensionnement, détruit l'argument (l'appel du destructeur dans la sortie).

0

Si vous initialisez des objets de cette façon le modèle vectoriel crée des objets en faisant une copie. Si vous ne voulez pas appeler un constructeur de copie vous devez faire:

vector<A*> Avec; 
avec.push_back(new A()); 

http://www.cplusplus.com/reference/stl/vector/vector/

+0

Je pense cela fera aussi deux allocations: - Un pour le nouveau A() - Un pour la copie de push_back() – ynimous

+0

@ynimous: Pas vraiment, le code ci-dessus change la sémantique pour que le vecteur contienne des pointeurs. Il créera un élément A une seule fois, alors qu'il créera et copiera le pointeur (ce qui est supposé être plus rapide). –

+1

Le problème avec cette approche est que vous changez la sémantique du code. Avant que les objets ne soient maintenus en valeur à l'intérieur du vecteur, la destruction du vecteur impliquait la destruction de tous les éléments contenus. Maintenant que les éléments sont maintenus à travers un pointeur, le code doit être adapté et l'utilisateur doit détruire toutes les ressources (objets A) manuellement. Tandis que vous avez réduit le nombre de constructions A, le code est maintenant plus fragile et sujet aux fuites de ressources. –

0

Voici une supposition:

  1. Le compilateur réordonne l'allocation initiale de Avec jusqu'après la « début resize »
  2. Le vecteur est d'abord attribué à 0 éléments
  3. Redimensionner obtient la nouvel élément rempli d'un A par défaut (qui a été réalisé en créant un A par défaut, en le copiant dans le vecteur, et en supprimant le caractère temporaire.)