1

Bon, je suis un peu un nioob en C++, mais je me pose tout de même quelques questions sur l'implémentation des vector.
Bêtement, je pensais que c'était grosso-modo une structure comprenant un bloc mémoire (avec malloc), la taille réelle, la taille occupée, des pointeurs vers le début et la fin.

Petit exemple de code :
#include <vector>
class toto {
    public:
        std::vector<int> tata;
};
int main(void) {
    toto titi;
    titi.tata.push_back(3);
    toto *tutu = new toto();
    tutu->tata.push_back(3);
    delete tutu;
    return 0;
}

Ça compile avec les options standards (-Wall -Wextra -pedantic), et valgrind ne me dit rien quand je l'exécute (no leaks are possible).

Comment se fait-il qu'il n'y ait pas besoin d'initialiser le vecteur et le bloc mémoire ? L'initialisation se fait-elle automatiquement ?

Comment se fait-il que valgrind ne râle pas alors que je n'ai pas utilisé clear ?
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

2

Parceque le constructeur et le desctructeur du vecteur se chargent respectivement d'allouer et de libérer toute la mémoire utilisée par les mécanismes internes de "vector" ? L'initialisation de "titi", l'appel à "new toto", la fin du main et ton "delete tutu" déclenchent le constructeur et le destructeur de vector, qui pour simplifier font les "malloc" et les "free" qui vont bien.

Je ne suis pas sûr d'avoir répondu à la question, le terme "bloc mémoire" m'intrigue. C'est le concept même de la POO que de te fournir un objet capable de faire un certain nombre de choses sans que tu n'aies à te soucier du fonctionnement interne. En l'occurrence, un vector permet de conserver un nombre arbitraire de valeurs consécutives, tu n'as pas besoin de savoir comment il fait et c'est son job de réaliser toutes les opérations nécessaires pour que ça se passe sans erreur et sans leak mémoire smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

3

(cross)

bin les réponses sont dans les questions grin

t'as mis un vecteur dans un objet alloué sur la pile, donc "toto titi;" appelle le constructeur sans arguments de ton objet. Ton objet contient un vecteur, lui aussi alloué sur la pile donc le constructeur sans argument de vector<int> est appelé, et je suppose que dans leur grande siouxerie les concepteurs du bidule ont défini une taille par défaut du vector sans argument grin

d'ailleurs le vector, si je ne m'abuse, il grandit tout seul si nécessaire.

du coup les destructeurs de toto et de vector sont aussi appelé quand on quitte le scope de ta variable locale, et et aussi qq part dans la spec du vector, doit y avoir écrit que le destructeur de vector appelle le destructeur de chaque élément puis fait harakiri à la fin, et dans le cas d'un type natif il doit juste faire harakiri cheeky

enfin chuis un noob aussi et faudrait sortir les docs de référence, mais si valgrind est OK, alors ça doit marcher comme ça grin

4

iwannabeamaki (./2) :
Parceque le constructeur et le desctructeur du vecteur se chargent respectivement d'allouer et de libérer toute la mémoire utilisée par les mécanismes internes de "vector" ? L'initialisation de "titi", l'appel à "new toto", la fin du main et ton "delete tutu" déclenchent le constructeur et le destructeur de vector, qui pour simplifier font les "malloc" et les "free" qui vont bien.

Je ne suis pas sûr d'avoir répondu à la question, le terme "bloc mémoire" m'intrigue. C'est le concept même de la POO que de te fournir un objet capable de faire un certain nombre de choses sans que tu n'aies à te soucier du fonctionnement interne. En l'occurrence, un vector permet de conserver un nombre arbitraire de valeurs consécutives, tu n'as pas besoin de savoir comment il fait et c'est son job de réaliser toutes les opérations nécessaires pour que ça se passe sans erreur et sans leak mémoire smile

Ok, merci pour la réponse, j'avais juste un doute ^^

Donc le constructeur par défaut de chaque attribut d'une classe est appelé lors de son instanciation, c'est ça ?
Mais que se passe-t-il s'il n'y a pas de constructeur par défaut ? (est-ce possible, en fait ? grin)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

5

Oui, les constructeurs des attributs sont appelés à la création de l'objet qui les contient. S'il n'y a pas de constructeur par défaut (c'est tout à fait possible, il suffit de créer toi-même une classe qui n'a pas de constructeur par défaut), alors il faudra que ton objet spécifie explicitement comment l'attribut doit être construit (tout mets ":" après le constructeur de l'objet parent, puis tu appelles les constructeurs des attributs à initialiser). Et si tu ne le fais pas, ça ne compilera tout simplement pas smile

Au passage, les POD (types "natifs") genre int, pointeurs & co acceptent tous un constructeur par défaut.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

6

iwannabeamaki (./5) :
S'il n'y a pas de constructeur par défaut (c'est tout à fait possible, il suffit de créer toi-même une classe qui n'a pas de constructeur par défaut)


il me semble qu'il y a un constructeur par defaut qui appelle juste le constructeur par defaut de tous les membres, non? (sauf si tu definis explicitement un constructeur qui prend des arguments)
avatar
I'm on a boat motherfucker, don't you ever forget

7

Et je ne crois pas qu'un vector ait de pointeur vers la fin, cf ./1. Je n'en vois pas l'utilité du moins, la fin de ce conteneur étant précisément très facile à calculer.

8

damnvoid (./6) :
il me semble qu'il y a un constructeur par defaut qui appelle juste le constructeur par defaut de tous les membres, non? (sauf si tu definis explicitement un constructeur qui prend des arguments)

Oui, uniquement si aucun des constructeurs en question ne prend d'argument. Flanker demandait ce qu'il se passait si l'un des attributs n'avait qu'un constructeur avec argument, et dans ce cas il n'y a pas d'autre solution que l'appeler explicitement.

[edit] illustration : struct A { A (int) {} }; struct B { A a; }; int main () { B b; }
$ g++ test.cc
test.cc: In constructor 'B::B()':
test.cc:8:1: error: no matching function for call to 'A::A()'
test.cc:4:2: note: candidates are: A::A(int)
test.cc:3:1: note:                 A::A(const A&)
test.cc: In function 'int main()':
test.cc:14:4: note: synthesized method 'B::B()' first required here
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

9

./7 > Sisi, il y a bien un "pointeur" vers la fin... Je met les guillemets parce que c'est du #C++# et qu'en fait c'est un pointeur mais en même temps, ce n'en est pas un. (De mémoire c'est un iterator)
Enfin bref, ça sert pour les itérateurs, et c'est assez pratique quand même... Malgré tout ça reste une vraie merde à utiliser...
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

10

Merci pour tous ces renseignements ^^ J'étais un peu trop resté sur une vision très bas niveau comme le C, où on doit tout faire à la main happy
Au moins, je comprends mieux comment ça fonctionne réellement (il n'est jamais trop tard pour découvrir le C++ embarrassed)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

11

Un truc intéressant à retenir sur les types POD, c'est qu'ils ont en fait un constructeur par défaut qui les initialise à zéro, mais seulement si on l'appelle explicitement:
int main(void)
{
	int a;               //non-initialisé
	int b = int();       //initialisé à zéro
	int *pa = new int;   //non-initialisé
	int *pb = new int(); //initialisé à zéro

	delete pa;
	delete pb;
}
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.