2013-08-31 2 views
0

Lorsque j'ai appris le C++, ils m'ont prévenu de ne pas utiliser le STL. C'était nouveau, bogué et inefficace. Récemment, je me suis trouvé en train de créer un conteneur pour un nouveau projet, et j'ai réalisé qu'il s'agissait probablement d'un cas de NIH et je devrais essayer le STL <vector>.Ancien programmeur a besoin de secrets STL

Malheureusement, cela ne fonctionne pas.

#include <stdio.h> 
#include <stdlib.h> 

#include <vector> 

class test { 
    public: 
    int x; 
}; 

int main(int argc,char *argv[]) { 
    std::vector<test> obj; 
    test *tmp=new test(); 
    tmp->x=42; 
    obj.push_back(tmp); 
    } 

g ++ me avertit qu'il n'y a pas de fonction concordante pour push_back, et que push_back prend const value_type & en tant que paramètre. J'ai essayé plusieurs castes pour forcer cela, mais il refuse de bouger.

J'ai maintenant perdu plus de temps à essayer de le faire de la «bonne» façon que ce qu'il aurait fallu pour écrire encore un autre conteneur et le déboguer.

Si cela ressemble à de la rage et de la frustration, vous êtes perspicace. J'ai déjà trouvé plusieurs questions comme la mienne, mais les réponses s'avèrent extraordinairement difficiles à suivre. Si c'était un site où les flammes voleraient, je m'attendrais à être grillé pour cela. Je me suis caché autour de stackoverflow pendant quelques années, et je parie qu'il y a quelqu'un qui pourrait "l'expliquer comme si j'avais cinq ans."

Y a-t-il une incantation à une seule couche pour forcer la distribution à fonctionner? Sinon, comment ces vecteurs sont-ils censés être utilisés?

+2

Pourquoi allouez-vous tmp sur le tas? aussi: 'obj.push_back (* tmp);' – Borgleader

+0

@Borgleader lui dites-vous de fuir l'objet? – sehe

+0

['push_back' ne prend pas un argument de pointeur] (http://en.cppreference.com/w/cpp/container/vector/push_back). –

Répondre

11

perdre le pointeur

std::vector<test> obj; 
test tmp; 
tmp.x=42; 
obj.push_back(tmp); 

Vous avez un vecteur de test ne test* donc je ne sais pas pourquoi vous avez essayé d'impliquer des pointeurs. L'un des avantages majeurs de la STL est qu'elle vous permet d'éviter les pointeurs, qui en tant que C++ expérimenté, je suis sûr que vous savez sont une cause majeure de bugs.

+0

Wow! C'était si simple? Je savais que je ne devrais pas l'implémenter à nouveau avec des pages de pointeur Je vais essayer d'arrêter de penser avec des pointeurs – user1017291

+1

Si vous êtes préoccupé par la performance, ne pensez jamais à penser avec des pointeurs: L'un des bugs de performance les plus fréquents avec les personnes utilisant des conteneurs standard est la tendance J'ai vu des gens faire des vecteurs de chaînes de caractères, puis je me demandais pourquoi attribuer tout ça est si lent ... Donc, je préconise aussi d'utiliser 'vector '. le vecteur 'et le vecteur ' ont leurs utilisations légitimes, n'ignorent jamais inutilement l'un ou l'autre. Sachez également que le fait de passer un objet à 'push_back()' le copie. – cmaster

3

Effectuez l'une de ces 2 choses

std::vector<test*> obj; 
test *tmp=new test; 
tmp->x=42; 
obj.push_back(tmp); 

Ou

std::vector<test> obj; 
test tmp; 
tmp.x=42; 
obj.push_back(tmp); 

Si vous déclarez un vector de test objets, push_back alors un objet test. Si vous déclarez des pointeurs vector de test, puis appuyez sur test *.

+3

Il est à noter que dans le premier cas, les destructeurs des objets de test ne seront pas appelés car le vecteur contient des pointeurs. Donc la 2ème version est préférée. – Borgleader

+0

Il devient compliqué d'apprendre à s'éloigner des pointeurs et de l'allocation des tas, mais cela vaut le coup d'être vu. La considération de la différence entre les deux solutions ci-dessus est de savoir si une copie de 'test tmp' est sûre/coûteuse à faire. Le premier bloc ne copie pas l'objet créé, tandis que le second crée une copie temporaire sur la pile et pousse une copie dans le vecteur. Notez que l'avantage de la méthode de copie est l'absence de nécessité de libérer ces pointeurs. – ash

+0

@ash Déplacez-vous si vous ne voulez pas copier. Ne fais pas la première chose. –

1

En plus de perdre le pointeur comme @John (à juste titre, à mon avis) a suggéré, je ferais ajouter un cteur à votre test classe:

class test { 
    int x; 
public: 
    test(int x) : x(x) {} 
}; 

Cela peut être utilisé pour une conversion implicite , de sorte que vous pouvez aussi sauter la variable tmp, laissant quelque chose comme:

std::vector<test> t; 

t.push_back(42); 

... et le compilateur utiliser le cteur pour convertir automatiquement le 42 à unObjetavec sa valeur x définie sur 42.

Si vous voulez protéger contre une conversion accidentelle d'un int aléatoire en un test, vous pouvez choisir un point à mi-chemin.Faire le explicit de cteur, et convertir explicitement dans l'appel à push_back:

class test { 
    int x; 
public: 
    explicit test(int x) : x(x) {} 
}; 

// ... 

std::vector<test> t; 

t.push_back(test(42)); 

Oh, je devrais probablement mentionner un autre détail: en supposant que vous utilisez un (assez) nouveau compilateur, vous pouvez utiliser à la place emplace_back de push_back. Si on lui donne une chance, il créera le nouvel objet en place au lieu de le copier dans le vecteur. Cela ne fera aucune différence pour une minuscule classe comme votre test (contenant seulement un seul int), mais pour quelque chose de grand qui coûte cher à copier, la différence peut être significative.

1

Vous ne devez pas stocker de pointeurs C++ dans des collections std. Vous stockez les objets eux-mêmes comme John le suggère. Une foule de bogues mémoire très délicate résulte de l'utilisation de pointeurs bruts.
Peut-être que votre professeur l'avait fait s'il croyait que le STL était bogué. C'est vraiment robuste. La STL peut sembler inefficace si vous stockez de gros objets dans des collections car ceux-ci seront copiés, ce qui est coûteux en temps et en mémoire. D'où la croyance à l'inefficacité qui est également fausse. L'astuce consiste à utiliser smart pointers. Ceux-ci rendent l'allocation de tas beaucoup plus facile et fonctionnent brillamment avec le STL. C'est alors efficace et pas du tout buggé. C'est beaucoup mieux que ce qui est raisonnable de s'inscrire.

+0

Les éléments vectoriels seront déplacés, non copiés, dans la mesure du possible. Sinon, un conseil correct et très judicieux. +1 * thumbs up * –

+0

lol - bugs et pointeurs difficiles. Sonne familier. Ils ont créé un langage de programmation complet, et des systèmes d'exploitation basés sur cela. – ash

+1

Même avec des éléments en copie seule, le souci de la vitesse de copie est * généralement * mal placé. En supposant que les éléments sont copiés, ils ne sont pas souvent copiés souvent - le nombre de fois a tendance à être constant, typiquement autour de 3. –