Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Warning

71 réponses
Avatar
Sébastien M.
Bonjour,

Cela vous semble-t-il normal que ce code compile normalement, sans
m=EAme un warning ?
(test=E9 avec gcc 3.4, VS 2003 et VS 2005)


#include<iostream>
using namespace std;

struct A
{
A() : a(0) {}
int a;
};

struct B : public A
{
B() : b(1), c(1), d(1) {}
int b,c,d;
};

int main()
{
A* tab =3D new B[16];

cout << '\n';
for(int i=3D0; i<16; i++)
{
cout << tab[i].a << ' ';
}
cout << endl;
}

10 réponses

1 2 3 4 5
Avatar
Sylvain SF
Mickaël Wolff wrote on 07/08/2008 22:26:
Sylvain SF a écrit :
l'opérateur [] appliqué à un tableau ignore tout de la virtualité,
son calcul d'offset (comme '++') n'utilise que la taille de son type
donc A (soit 1 int).



C'est ce qui explique que, si je rajoute des destructeurs virtuels, un
delete [] tab segfault ?



il y a en effet des chances que le delete du second élément mette la
cata. (le "iterate_delete_item_from_array" fait un appel virtuel
correct, mais le calcul de l'offset de l'élément suivant est mauvais).

Sylvain.
Avatar
Fabien LE LEZ
On Thu, 7 Aug 2008 08:38:00 -0700 (PDT), Sébastien M. :

Oui mais malheureusement on doit parfois utiliser des APIs mal faites
qui nous obligent à faire ce genre de choses ( new[] à la place de
vector ).



Uh ? Dans quel cas ?

Si tu as une fonction (dans une bibliothèque, typiquement écrite en C)
de ce style :
int f (char* ptr, size_t lng);
tu peux écrire :

std::vector <char> buf (la_taille_voulue);
f (&buf[0], buf.size());

Il me semble que l'usage de new[] est si rare qu'il justifie, à chaque
usage, un commentaire indiquant pourquoi on n'a pas utilisé une autre
solution.
Avatar
James Kanze
On Aug 7, 9:52 pm, Sylvain SF wrote:
Sébastien M. wrote on 07/08/2008 17:27:
>> Puis-je demander pour quelle raison on pourrait s'attendre
>> à un warning?



> C'est un comportement indéfini.



> Pour les compilateurs avec lesquels j'ai fait les tests, le
> programme affiche ceci :
> 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1



car A est un POD de taille "1" (en posant qu'un int à une
taille de une unité) et B un POD de 4 unités.



le new B[] alloue (et initialise) bien un tableau de POD de
taille 4, mais la boucle balaye un A[], en fait on affiche
(syntaxe abusive):



tab[0].a, tab[0].b, tab[0].c, tab[0].d, tab[1].a, tab[1].b, tab[1].c,
tab[1].d, etc



l'allocation A* tab = new B[4]; avec la boucle (int i=0; i<16;
++i) donnerait le même résultat et pas d'erreur d'accès hors
buffer (or cas d'alignement particulier ou autre "indéfini").



l'opérateur [] appliqué à un tableau ignore tout de la
virtualité, son calcul d'offset (comme '++') n'utilise que la
taille de son type donc A (soit 1 int).



Ça explique ce qui se passe probablement dans l'implémentation
(et c'est en effet la justification du comportement indéfini),
mais pour l'utilisateur : l'arithmétique sur pointeurs (et donc
l'indexation, qui est définie en termes d'arithmétique sur
pointeurs) n'est défini qu'à l'intérieur d'un tableau, avec des
pointeurs à des éléments du tableau (ou un au-delà de la fin du
tableau). Et que si tu as un tableau de B, un A* ne pourrait
jamais désigner un élément du tableau, parce que les éléments ne
sont pas des A.

std::vector n'est pas obligeatoire (je n'utilise jamais
'cette' version) mais un tableau doit autant que faire ce peut
conserver son type vrai.



std::vector se comporte plus ou moins comme un tableau classique
à cet égard.

--
James Kanze (GABI Software) email:
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
James Kanze
On Aug 7, 10:26 pm, Mickaël Wolff wrote:
Sylvain SF a écrit :



> l'opérateur [] appliqué à un tableau ignore tout de la
> virtualité, son calcul d'offset (comme '++') n'utilise que
> la taille de son type donc A (soit 1 int).



C'est ce qui explique que, si je rajoute des destructeurs
virtuels, un delete [] tab segfault ?



Surtout, ce qui l'explique, c'est que la norme dit que dans un
delete[], si le type dynamique n'est pas le même que le type
statique, c'est un comportement indéfini. (Mais la motivation
est la même : il a besoin de l'arithmétique sur pointeurs, qui
suppose que le compilateur connaissent la taille réele de
l'objet.)

--
James Kanze (GABI Software) email:
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
James Kanze
On Aug 8, 4:46 am, Fabien LE LEZ wrote:
On Thu, 7 Aug 2008 08:38:00 -0700 (PDT), Sébastien M. :



[...]
Il me semble que l'usage de new[] est si rare qu'il justifie,
à chaque usage, un commentaire indiquant pourquoi on n'a pas
utilisé une autre solution.



Pour confirmer : je pratique le C++ depuis prèsque 20 ans, à
tous les niveaux (de l'implémentation des vecteur et des chaînes
à l'époque avant la norme, jusqu'aux applications complètes), et
je n'ai jamais eu la moindre occasion d'utiliser un new[].

--
James Kanze (GABI Software) email:
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
Sébastien M.
On 8 août, 04:46, Fabien LE LEZ wrote:
On Thu, 7 Aug 2008 08:38:00 -0700 (PDT), Sébastien M. :

>Oui mais malheureusement on doit parfois utiliser des APIs mal faites
>qui nous obligent à faire ce genre de choses ( new[] à la place de
>vector ).

Uh ? Dans quel cas ?




Dans cette API, on est sensé hérité d'une classe mère pour ajouté des
comportement.

Il y a des donnée 'protected' de la classe mère qui doivent être
initialisées par les classes filles dont un tableau d'objet. Cette
nouvelle classe doit faire le new sinon la classe mère n'a pas ce
quelle veut ... (évidement on n'a pas accès au code de la classe mère )

Enfin ... le coté positif c'est que je ne vais bientôt plus travailler
sur ce truc :-D

--
Sébastien
Avatar
Sébastien M.
>
Pour confirmer : je pratique le C++ depuis prèsque 20 ans, à
tous les niveaux (de l'implémentation des vecteur et des chaînes
à l'époque avant la norme, jusqu'aux applications complètes), et
je n'ai jamais eu la moindre occasion d'utiliser un new[].




Sauf si on utilise un "allocator" développé par quelqu'un d'autre je
pense qu'on doit avoir au moins un new dans le programme si on
implémente soit même les classes de base :-D

Après je suis d'accord qu'on ne doit pas avoir de "new" si on utilise
la STL et pas plus d'un "new" si on implémente tout depuis le début.

--
Sébastien
Avatar
Fabien LE LEZ
On Fri, 8 Aug 2008 02:16:59 -0700 (PDT), Sébastien M.
:

Dans cette API, on est sensé hérité d'une classe mère pour ajouté des



Par pitié, relis ta prose avant de poster !

Il y a des donnée 'protected' de la classe mère qui doivent être
initialisées par les classes filles dont un tableau d'objet.



Gnii ? J'ai l'impression que c'est un bon candidat pour
<http://thedailywtf.com/> :-/

Enfin ... le coté positif c'est que je ne vais bientôt plus travailler
sur ce truc :-D



J'imagine que ça va beaucoup te soulager.
Avatar
Sébastien M.
> >Dans cette API, on est sensé hérité d'une classe mère pour ajout é des

Par pitié, relis ta prose avant de poster !



oups :-( désolé.

>Il y a des donnée 'protected' de la classe mère qui doivent être
>initialisées par les classes filles dont un tableau d'objet.

Gnii ? J'ai l'impression que c'est un bon candidat pour
<http://thedailywtf.com/> :-/



oui, je pense qu'on pourrait même faire une série d'articles.

>Enfin ... le coté positif c'est que je ne vais bientôt plus travaill er
>sur ce truc :-D

J'imagine que ça va beaucoup te soulager.



oh oui.
Avatar
Jean-Marc Bourguet
Sébastien M. writes:

>
> Pour confirmer : je pratique le C++ depuis prèsque 20 ans, à
> tous les niveaux (de l'implémentation des vecteur et des chaînes
> à l'époque avant la norme, jusqu'aux applications complètes), et
> je n'ai jamais eu la moindre occasion d'utiliser un new[].
>

Sauf si on utilise un "allocator" développé par quelqu'un d'autre je
pense qu'on doit avoir au moins un new dans le programme si on
implémente soit même les classes de base :-D



Il a ecrit new[] pas new.

(Je dois en avoir ecrit mais je ne me souviens pas d'occasions ou vector<>
ou une classe similaire n'aurait pas ete en fait une meilleure solution).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
1 2 3 4 5