OVH Cloud OVH Cloud

Tableaux et stl

42 réponses
Avatar
JM
Bonjour

Toujours plongé dans la stl, j'ai quelques questions (Pas évident de
trouver un tutoriel à la fois clair et compréhensible)

0) Où peut-on trouver un bon tutoriel (Français de préférence, mais à
défaut, l'anglais me conviendra)

1)
J'ai une classe :
class CA
{public
CA() { initialisations divers et variées; }
~CA();

void f();
}

vector<CA> tableau;

tableau.size(10);

Le constructeur est-il bien appelé pour les 10 éléments?
Je pense que oui mais le doute est en moi.

2) Toujours avec la classe précédente.

Je veux ajouter un élément à la fin de mon tableau.
A priori, tableau.push_back ne peut-être utilisé sans passer de référence.

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.

b) tableau.resize(tableau.size()+1)

Cela me parait un peu bourrin, mais c'est le seul truc que j'ai pu
trouver dans les tutoriels que j'ai vus.


y'a-t-il d'autres possibilités, sachant que toutes les initialisations
dont j'ai besoin sont faites dans le constructeur?

3) Jusqu'à présent, style C oblige, j'utilisais toujours une variable
pour conserver la taille de mon tableau.

Je suppose que cette manière de faire est obsolète avec size() ?

Merci d'avance à ceux qui répondront à ces questions certainement niveau
0, mais j'avoue que cela m'aidera bien!

10 réponses

1 2 3 4 5
Avatar
Fabien LE LEZ
On Mon, 18 Sep 2006 17:53:27 +0200, JM :

tableau.size(10);


vector<>::size() ne prend pas d'argument, et renvoie le nombre actuel
d'éléments.

Tu voulais peut-être écrire .resize(10) ?

Le constructeur est-il bien appelé pour les 10 éléments?


Oui.

A priori, tableau.push_back ne peut-être utilisé sans passer de référence.


Disons que si tu veux ajouter un élément, il faut lui indiquer quoi
ajouter, effectivement.

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.


Pourquoi ? Quel est le problème ?

b) tableau.resize(tableau.size()+1)

Cela me parait un peu bourrin,


Effectivement, c'est pas terrible :-(


3) Jusqu'à présent, style C oblige, j'utilisais toujours une variable
pour conserver la taille de mon tableau.

Je suppose que cette manière de faire est obsolète avec size() ?


Effectivement.

Avatar
Sylvain
Fabien LE LEZ wrote on 18/09/2006 18:21:

A priori, tableau.push_back ne peut-être utilisé sans passer de référence.


Disons que si tu veux ajouter un élément, il faut lui indiquer quoi
ajouter, effectivement.


je n'ai pas lu qu'il souhaitais ajouter "rien", mais était géné
d'ajouter une *référence* (et non un pointeur).

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.


Pourquoi ? Quel est le problème ?


ben parce que "cela créé un temporaire" !

- on peux vouloir la "classe vectorisée" non copiable.
- on peux, en effet, trouver étonnant le fait de transmettre un truc ne
servant qu'à être jeté (création tempo, instantiation ptr, recopie,
destruction; tout ça à la place d'une simple affectation de pointeur ne
parait pas très vertueux).

Sylvain.


Avatar
JM

Tu voulais peut-être écrire .resize(10) ?


Tout à fait!


Le constructeur est-il bien appelé pour les 10 éléments?


Oui.


Ok, ça paraissait logique, mais bon.

A priori, tableau.push_back ne peut-être utilisé sans passer de référence.


Disons que si tu veux ajouter un élément, il faut lui indiquer quoi
ajouter, effectivement.


Disons que cela me facilitait la tache.
Il va juste falloir que je redéfinisse mon constructeur, c'est pas trop
gênant.

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.


Pourquoi ? Quel est le problème ?


Quand c'est une instruction très fréquente, cela doit être plutôt
pénalisant, non?

3) Jusqu'à présent, style C oblige, j'utilisais toujours une variable
pour conserver la taille de mon tableau.

Je suppose que cette manière de faire est obsolète avec size() ?


Effectivement.


Ok, merci.

J'ai l'impression que les STL facilitent bien la vie, mais cela implique
de prendre de nouvelles habitudes :o)


Avatar
JM

ben parce que "cela créé un temporaire" !

- on peux vouloir la "classe vectorisée" non copiable.
- on peux, en effet, trouver étonnant le fait de transmettre un truc ne
servant qu'à être jeté (création tempo, instantiation ptr, recopie,
destruction; tout ça à la place d'une simple affectation de pointeur ne
parait pas très vertueux).



Tout à fait
J'ai résolu le problème en changeant mon constructeur.
C'est finalement devenu plus propre et plus clair.

Avatar
Jean-Marc Desperrier
JM wrote:
Je veux ajouter un élément à la fin de mon tableau.
A priori, tableau.push_back ne peut-être utilisé sans passer de référence.

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me convient
pas trop.

b) tableau.resize(tableau.size()+1)

Cela me parait un peu bourrin, mais c'est le seul truc que j'ai pu
trouver dans les tutoriels que j'ai vus.

y'a-t-il d'autres possibilités, sachant que toutes les initialisations
dont j'ai besoin sont faites dans le constructeur?


Si tu as un problème de ce type, il me semble que c'est a priori que tu
ferais mieux d'éviter std::vector et d'utiliser plutôt une std::list :
tu sous-entends qu'il est ici lourd et à éviter que de créer un
temporaire pour copie. Or le vecteur fait cela tout le temps dès que la
taille change, et le list permet de l'éviter.

La contre-partie est de perdre l'accès en temps constant à n'importe
quel élément, mais il faut juste voir lequel des deux est le plus important.

Si l'accès en temps constant est vraiment important ensuite, on peut
aussi décider de calculer une borne supérieure au nombre d'éléments
nécessaires, de faire un v.reserve, puis d'utiliser v.resize(v.size()+1)
et v.back().

Ou regarder si ce n'est pas le std::deque qui serait le meilleur compromis.

Avatar
kanze
Sylvain wrote:
Fabien LE LEZ wrote on 18/09/2006 18:21:

A priori, tableau.push_back ne peut-être utilisé sans
passer de référence.


Disons que si tu veux ajouter un élément, il faut lui indiquer quoi
ajouter, effectivement.


je n'ai pas lu qu'il souhaitais ajouter "rien", mais était
géné d'ajouter une *référence* (et non un pointeur).

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.


Pourquoi ? Quel est le problème ?


ben parce que "cela créé un temporaire" !


C'est un peu la philosophie de base de C++. On a des temporaires
sur la pile, plutôt que seulement des objets créés
dynamiquement.

- on peux vouloir la "classe vectorisée" non copiable.


On ne peut pas. C'est contre la philosophie de base. (En fait,
je vois mal comment ça serait implémentable.)

- on peux, en effet, trouver étonnant le fait de transmettre
un truc ne servant qu'à être jeté (création tempo,
instantiation ptr, recopie, destruction; tout ça à la place
d'une simple affectation de pointeur ne parait pas très
vertueux).


Et quelle est l'alternative ? Crée tout dynamiquement, et ne
travailler qu'avec des pointeurs ?

À la fin, il faut comprendre le langage. Il permet bien les deux
modèles ; la sémantique de valeur, c'est le défaut, mais il a
tout ce qu'il faut pour implémenter la sémantique de référence
quand on en a besoin.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
JM wrote:

A priori, tableau.push_back ne peut-être utilisé sans
passer de référence.


Disons que si tu veux ajouter un élément, il faut lui
indiquer quoi ajouter, effectivement.


Disons que cela me facilitait la tache. Il va juste falloir
que je redéfinisse mon constructeur, c'est pas trop gênant.


Il faut bien définir la sémantique de ta classe. Et si elle n'a
pas une sémantique de valeur (avec la copie, etc.), on ne peut
pas le mettre dans un tableau. Il existe alors d'autres
solutiones, des tableaux de pointeurs, etc.

Vu que cela crée un objet temporaire sur la pile, cela
ne me convient pas trop.


Pourquoi ? Quel est le problème ?


Quand c'est une instruction très fréquente, cela doit être
plutôt pénalisant, non?


Par rapport à quoi ?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Fabien LE LEZ wrote:
On Mon, 18 Sep 2006 17:53:27 +0200, JM :

b) tableau.resize(tableau.size()+1)

Cela me parait un peu bourrin,


Effectivement, c'est pas terrible :-(


Note aussi en plus que ça risque de créer un élément temporaire
quelque part aussi, qu'on copie.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Alain Gaillard


- on peux vouloir la "classe vectorisée" non copiable.
- on peux, en effet, trouver étonnant le fait de transmettre un truc ne
servant qu'à être jeté (création tempo, instantiation ptr, recopie,
destruction; tout ça à la place d'une simple affectation de pointeur ne
parait pas très vertueux).


Comment ça, simple affectation de pointeur ?

--
Alain

Avatar
Sylvain
kanze wrote on 18/09/2006 19:12:

ben parce que "cela créé un temporaire" !


C'est un peu la philosophie de base de C++. On a des temporaires
sur la pile, plutôt que seulement des objets créés
dynamiquement.


j'aime cette philosophie, la coexistence de variables statiques ET
dynamiques me va très bien également; non, je ne vois pas comment
efficacement sans passer.

c'est ici seulement l'interface de vector<> dont il est question.

- on peux vouloir la "classe vectorisée" non copiable.


On ne peut pas. C'est contre la philosophie de base. (En fait,
je vois mal comment ça serait implémentable.)


je suis également d'accord avec les exigences du contrat de vector<>, je
soulignais le trait pour indiquer qu'il a *IMHO* un caractère négatif.

il reste toutefois des cas où on a bien affaire à des instances qui
doivent être non copiables (wrapper de resources physiques par exemple,
ou gestionnaire d'accès à une source non multi-entrante, etc); de tels
gestionnaires ne peuvent pas être regroupés / utilisés via un vector<>.

- on peux, en effet, trouver étonnant le fait de transmettre
un truc ne servant qu'à être jeté (création tempo,
instantiation ptr, recopie, destruction; tout ça à la place
d'une simple affectation de pointeur ne parait pas très
vertueux).


Et quelle est l'alternative ? Crée tout dynamiquement, et ne
travailler qu'avec des pointeurs ?


une alternative simple serait de pouvoir transmettre un T* (et même tout
pointeur sur une classe assimilable à un T (T et ses sous classes)).

l'organisation interne de vector<> passe nécessairement par des
pointeurs de la classe template, n'imposer que des références à
l'insertion ne me parait pas si indispensable. (ok, tu vas me répondre
que je n'ai pas le droit de lire la définition du template ou d'en tirer
des conclusions).

si la question était ouverte ("si" parce que heureusement 99% des
utilisateurs se foutent de l'avis qui suit), le mérite de vector<> est
son mécanisme allocator customisable (justement pour traiter les
références) et son redimensionnement, dans un second temps ses itérateurs.

les 2 premiers points garantissent de travailler avec des références
(T&), c'est comme cela que je travaille dès que possible donc il ne
s'agirait pas de "travailler avec des pointeurs", surtout pas; par
contre je ne trouverais pas gênant de faire un push(new T(...)).

À la fin, il faut comprendre le langage. Il permet bien les deux
modèles ; la sémantique de valeur, c'est le défaut, mais il a
tout ce qu'il faut pour implémenter la sémantique de référence
quand on en a besoin.


je sais ce qu'est un tempo vs une référence, la question n'était pas là
il me semble.

Sylvain.


1 2 3 4 5