web-dev-qa-db-fra.com

Conteneurs STL avec référence à des objets

Je sais que les conteneurs STL copient les objets. Alors dis que j'ai un 

list<SampleClass> l;

chaque fois que je fais 

SampleClass t(...);
l.Push_back(t);

une copie de t sera faite. Si SampleClass est volumineux, cela coûtera très cher. 

Mais si je déclare que je suis un conteneur de références, 

list<SampleClass&> l;

Quand je fais 

l.Push_back(t);

Evitera-t-il de copier les objets?

26
CodeNoob

Malheureusement non, il ne compilera pas (avec stlport du moins). Mais l’alternative, qui consiste à stocker des pointeurs sur vos objets dans le conteneur, se compilera parfaitement.

Cela vous laissera un peu de bruit syntaxique supplémentaire autour de votre code - vous devrez faire de nouvelles choses pour les insérer dans votre conteneur.

std::list<class_type*> l;
l.Push_back(new class_type);

Bien que les objets ne soient pas copiés, ils ne seront pas automatiquement nettoyés pour vous lorsque la liste sera détruite. Les pointeurs intelligents résoudront ce problème pour vous, mais au prix d'un bruit syntaxique encore plus important. Et comme vous ne pouvez pas placer std :: auto_ptr dans des conteneurs standard car ils ne peuvent pas être copiés, vous devez utiliser leurs cousins ​​boost légèrement plus lourds, des pointeurs partagés.

std::list<boost::shared_ptr<class_type> > l;
l.Push_back(boost::shared_ptr<class_type>(new class_type));

Les pointes partagées entraînent des frais supplémentaires, mais elles sont minimes.

18
Dave Branton

Si vous savez ce que vous faites, vous pouvez créer un vecteur de références à l'aide de std::reference_wrapper:

#include <functional>
#include <vector>

int main()
{
  std::vector<std::reference_wrapper<int>> iv;

  int a = 12;
  iv.Push_back(a);  // or std::ref(a)

  // now iv = { 12 };

  a = 13;

  // now iv = { 13 };
}

Notez bien sûr que tout cela va s’effondrer sur vous si l’une des variables référencées sort de la portée pendant que vous conservez des références à celles-ci.

31
Kerrek SB

Les conteneurs de bibliothèque standard exigent que leurs types soient copiables; comme les références ne le sont pas, vous ne pouvez pas les stocker dans des conteneurs. Vous pouvez stocker des pointeurs tant que vous êtes attentif à la durée de vie des objets. Boost a des conteneurs de pointeurs pour vous aider, ou vous avez des pointeurs intelligents. Notez cependant que auto_ptr est non copiable (comme le définit la norme à cette fin), donc shared_ptr et unique_ptr sont vos meilleurs résultats maintenant. Les deux sont standard en C++ 11 et le premier est pris en charge via boost en C++ 03. 

4
Dennis Zickefoose

Maintenant que vous avez le pointeur intelligent, vous pouvez l'utiliser pour gérer la mémoire et en extraire des pointeurs bruts à utiliser dans les conteneurs STL. De cette façon, vous gardez la propriété du conteneur.

Ici, j'ai un unique_ptr d'un arbre, mais j'ai utilisé la pile STL pour stocker les pointeurs bruts

void TreeTraversal(unique_ptr<BinaryTreeNode>& root) {
    stack<BinaryTreeNode *> _stack;

    BinaryTreeNode *p = root.get();
    _stack.Push(p);

    while(!_stack.empty()) {
        p = _stack.top();
        _stack.pop();
        ...
        _stack.Push(p->left);
        _stack.Push(p->right);
    }
}

int main() {
    unique_ptr<BinaryTreeNode> root = unique_ptr<BinaryTreeNode>(new BinaryTreeNode(...));
    TreeTraversal(root);
}
0
saha

Vous voulez un conteneur de pointeurs: 

list<SampleClass*> l;
0
Mikhail