OVH Cloud OVH Cloud

Séquence des élèments d'un vector

36 réponses
Avatar
hyronn
Bonsoir,

Est-on assur=E9 que les =E9l=E9ments d'un std::vector se suivent en m=E9moi=
re?
Je veux utiliser un vector pour me d=E9charger de l'allocation dynamique
t'un tableau temporaire de caract=E8res.

#include <cstdio>
#include <vector>

void parse1(const char* const txt_buffer)
{
vector<char> str;
str.reserve(FILENAME_MAX);
sscanf(txt_buffer, " %*s \" %s ", (char*) &str[0] );
}

Ca marche sous VC++ 2003.
Mais est-ce standard et/ou portable?

J'ai aussi essay=E9 ceci, mais =E7a ne marche pas dans tous les cas et
=E9clanche parfois des exceptions. Je soupsonne l'impl=E9mentation de ne
pas vraiment effectuer le reserve().

void parse2(const char* const txt_buffer)
{
string s;
s.reserve(FILENAME_MAX);
sscanf(txt_buffer, " %*s \" %s ", const_cast<char*>(s.data()) );
}

Rq: je ne peux pas me permettre d'utiliser les iostreams pour des
raisons de performance. La fonction parser doit interpr=E9ter des
fichiers de plusieurs centaines de ko de texte.

Merci

10 réponses

1 2 3 4
Avatar
Loïc Joly
On Mar 18, 5:07 pm, Mathias Gaunard wrote:



Un pile usuelle fait dans les 8k




Une pile usuelle de 1980 ?
Un compilateur pourrait a priori détecter, modulo l'usage de la
récursivité, de quelle taille la pile doit être et t'avertir dans le cas
où la pile nécessaire serait trop grande.



C'est ce que faisait des compilateurs anno 1980. On y est un peu
revenu parce que les tailles qu'ils trouvaient étaient
exhorbitantes. En fait, ce que le compilateur sait trouver,
c'est la taille qu'utilise chaque fonction. Ensuite, il faut
analyser tous les chemins dans la graphe des appels pour en
trouver le plus long.

Dans la pratique, évidemment, sur une machine moderne, la taille
de la pile ne serait pas 8 Ko, mais 8 Mo, ou plus. Je me
démande, d'ailleurs, si le posteur original ne s'est pas trompé
d'unités. Chez moi, on précise bien que la taille de la pile,
c'est 8192 sur une machine, 10240 sur l'autre. Mais l'unité,
c'est des Ko, et non des octets. (Et évidemment, on peut
l'agrandir si besoin y est.)


et MAX_PATH (constante windowsienne
similaire) fait 32k




Un chemin et un nom de fichier c'est pas exactement la même chose.



Auriez-vous l'aimabilité de rapporter la valeur de FILENAME_MAX sur
vos implémentation ;-)




Le plus long nom possible que j'ai trouvé en regardant les
caractéristiques des systèmes de fichiers c'est 4032 octets.



Mais 255 est quand même une valeur récurrente.



J'ai 1024 sur une machine, 4096 sur l'autre. VC++ dit 260, mais
je me démande... Qu'est-ce qui se passe si je monte un système
de fichiers qui a des noms plus longs. Sous Posix, évidemment,
j'utiliserais plutôt « pathconf( dirname, _PC_NAME_MAX ) », de
façon à savoir pour le système de fichiers en question, mais je
ne connais pas l'équivalent sous Windows. (Il doit bien en
avoir ; sinon, le système serait difficilement utilisable dans
un reseau.)


Windows possède deux façons pour saisir les chemins, L'une limitée à
MAX_PATH, et l'autre à environ 32000 (on doit saisir les chemins en wide
char, et sous la forme "?C:Mon chemin" ou
"?UNC<server><share>"). PLus d'infos sur
http://msdn2.microsoft.com/en-us/library/aa365247.aspx.

Par contre, tous le logiciels n'arrivent pas forcément à s'y retrouver
avec ces chemins... Et je crois que Microsoft Office a déjà des
problèmes avant MAX_PATH.

--
Loïc



Avatar
Fabien LE LEZ
On Mon, 19 Mar 2007 17:39:03 +0100, Michel Decima
:

Peut etre que l'optimiseur est un peu benêt, il ne sais pas detecter
les constantes tout seul, et il faut l'aider un peu... mais j'ai un
gros doute quand meme, faut pas sous-estimer les capacités de ce genre
d'engins.


Surtout, si tu es dans un cas où tu as besoin de bonnes performances,
tu commences par sélectionner un compilateur capable d'optimiser
correctement...

Avatar
Franck Branjonneau
Sylvain Togni <"sylvain.togni at visionobjects.com"> écrivait:

Je ne sais pas, la seule différence que je vois c'est qu'en
utilisant const on est assez souvent amené à définir deux fois
certaines fonctions comme les getteurs, une version const et
une version non-const, ce qui augmente la taille du code et
diminue un peu la vitesse pour des raisons de localité.


Moi, un getteur non const j'appelle ça un setteur.

--
Franck Branjonneau

Avatar
James Kanze
On Mar 19, 9:04 pm, Loïc Joly
wrote:

On Mar 18, 5:07 pm, Mathias Gaunard wrote:



Un pile usuelle fait dans les 8k


Une pile usuelle de 1980 ?
Un compilateur pourrait a priori détecter, modulo l'usage de la
récursivité, de quelle taille la pile doit être et t'avertir dans le cas
où la pile nécessaire serait trop grande.


C'est ce que faisait des compilateurs anno 1980. On y est un peu
revenu parce que les tailles qu'ils trouvaient étaient
exhorbitantes. En fait, ce que le compilateur sait trouver,
c'est la taille qu'utilise chaque fonction. Ensuite, il faut
analyser tous les chemins dans la graphe des appels pour en
trouver le plus long.

Dans la pratique, évidemment, sur une machine moderne, la taille
de la pile ne serait pas 8 Ko, mais 8 Mo, ou plus. Je me
démande, d'ailleurs, si le posteur original ne s'est pas trompé
d'unités. Chez moi, on précise bien que la taille de la pile,
c'est 8192 sur une machine, 10240 sur l'autre. Mais l'unité,
c'est des Ko, et non des octets. (Et évidemment, on peut
l'agrandir si besoin y est.)

et MAX_PATH (constante windowsienne
similaire) fait 32k


Un chemin et un nom de fichier c'est pas exactement la même chose.

Auriez-vous l'aimabilité de rapporter la valeur de FILENAME_MAX sur
vos implémentation ;-)


Le plus long nom possible que j'ai trouvé en regardant les
caractéristiques des systèmes de fichiers c'est 4032 octets.

Mais 255 est quand même une valeur récurrente.


J'ai 1024 sur une machine, 4096 sur l'autre. VC++ dit 260, mais
je me démande... Qu'est-ce qui se passe si je monte un système
de fichiers qui a des noms plus longs. Sous Posix, évidemment,
j'utiliserais plutôt « pathconf( dirname, _PC_NAME_MAX ) », de
façon à savoir pour le système de fichiers en question, mais je
ne connais pas l'équivalent sous Windows. (Il doit bien en
avoir ; sinon, le système serait difficilement utilisable dans
un reseau.)


Windows possède deux façons pour saisir les chemins, L'une limitée à
MAX_PATH, et l'autre à environ 32000 (on doit saisir les chemins en wide
char, et sous la forme "?C:Mon chemin" ou
"?UNC<server><share>"). PLus d'infos surhttp://msdn2.microsoft.com/e n-us/library/aa365247.aspx.


J'ai lu ça aussi il n'y a pas si longtemps. Mais je ne sais pas
ce que ça signifie réelement ; probablement juste que le
système peut traiter des noms de cette taille.

Note bien aussi qu'ici, il ne s'agit pas de la taille du chemin
complet, mais de la taille maximum d'un nom de fichier. Qui
dépend surtout du système de fichiers où se trouve le fichier ;
sur ma machine Windows, j'ai des fichiers locaux (NTFS, je
crois) et des fichiers montés sous Samba sur Linux. Et il n'y a
aucune raison pourque la taille maximum d'un nom de fichier soit
la même sur les deux. C'est pour ça que la taille max. n'est pas
une constante, mais plutôt le résultat d'un appel d'une
fonction, et qu'il faut donné déjà le nom du répertoire à la
fonction, pour qu'elle puisse trouver le bon système de
fichiers.

(Dans le cas des fichiers monté sous Samba, il y a même deux
couches à prendre en compte ; la taille maximum d'un nom de
fichier, c'est le minimum de la taille maximum sous Linux, et la
taille maximum que supporte SMB. Mais je crois que SMB est assez
transparent à cet égard, et n'introduit pas vraiment de limite
supplémentaire.)

Par contre, tous le logiciels n'arrivent pas forcément à s'y retrouver
avec ces chemins... Et je crois que Microsoft Office a déjà des
problèmes avant MAX_PATH.


C'est toujours un problème avec le progrès. Je me rappelle quand
Unix a laissé tomber la restriction à 14 caractères. Il a fallu
un certain temps (et même un temps certain) avant que toutes les
applications suivent. Donc, par exemple, Sun CC (4.0) générait
des noms de fichier dans son « repository » (d'instantiations
des templates) basés sur le nom manglé, donc avec le nom de la
class, suivi du nom des types d'instantiation, etc. ; 40
caractères ou plus n'en était pas rare. Pour en créer une
bibliothèque, il faisait la fermature transitive, ajoutant ces
fichiers d'instantiation à la bibliothèque. Seulement,
l'utilitaire bibliothècaire, ar, tronquait les noms à 14
caractères. Ce qui faisait que beaucoup de noms finissaient par
être identiques, et que seulement le dernier qu'il trouvait se
trouvait réelement dans la bibliothèque.

Il y a eu un patch d'urgence, mais en attendant, pour générer
des bibliothèques avec Sun CC, il fallait utiliser le ar de GNU,
et non celui de Sun.

--
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 Mar 19, 10:55 am, Sylvain Togni <"sylvain.togni at
visionobjects.com"> wrote:
wrote:
J'indique au compilateur que txt_buffer ne sera pas modifié afin qu'il
puisse effectuer une optimisation dont je n'ai peut être pas
connaissance.


Petite précision : le mot-clé const n'a aucune incidence
sur les performances, il sert juste à éviter certains bugs
et à améliorer la lisibilité du code.


Ça dépend, d'où on s'en sert, et du compilateur.

Il y a des contextes où il est quasiment obligatoire. Une
variable const de type entier, si elle est initialisée par une
expression constante, et elle même une expression constante, au
sens de la norme. Donc :

int const n = 100 ;
char buf[ n ] ;

est légal ; supprimer le const, et elle ne l'est pas.

Sinon, prèsque tous les compilateurs profitent de quand ils
savent avoir à faire à un objet const.

En revanche, pointeur vers const ni référence vers const ne
change rien pour le compilateur, parce qu'ils ne garantissent
pas que l'objet ne peut pas changer de valeur.

--
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 Mar 19, 1:14 pm, "" wrote:
On 19 mar, 10:55, Sylvain Togni <"sylvain.togni at visionobjects.com">
wrote:

wrote:
J'indique au compilateur que txt_buffer ne sera pas modifié afin qu 'il
puisse effectuer une optimisation dont je n'ai peut être pas
connaissance.


Petite précision : le mot-clé const n'a aucune incidence
sur les performances, il sert juste à éviter certains bugs
et à améliorer la lisibilité du code.


D'autres confirment?
Ca serait très décevant de la part des compilateurs.

Par exemple:
on fixe une valeur et par la suite on a besoin de sa racine:
const float pi = 7;
float f = sqrt(pi).

Si un compilateur soit disant évolué appelle sqrt à chaque itérat ion,
il est pas très malin puisque pi et sqrt sont connues au moment de la
compilation*.


Il le fait, en revanche. Parce que comment sait-il que sqrt(7)
renvoie toujours la même valeur ?

En revanche, si tu as quelque chose du genre :

double const pi = 3.14159 ;

double x = sin( 2 * pi * r ) ;

il est fort probable qu'il n'execute le 2*pi qu'une seule fois,
probablement même lors de la compilation.

Je m'attend à ce que ces 2 lignes, écrites ainsi pour
assurer la lisibilité du code, soient remplacée par l'équivalent en
langage machine de
float f = 1.772004515;


Ce qui n'est possible que si le compilateur peut « voir » dans
sqrt.

* sqrt n'est pas vraiment "connue" au moment de la compilation, c'est
une fonction surement déclarée hors de l'unité de traduction courra nt.
Mais GCC compile jusqu'en 3 passes (-O3) et Visual C++ retarde une
partie de la compilation au liage de l'application ("whole program
optimizations"). Il y a donc, dans les 2cas, moyen de "remplacer"
sqrt(pi) par 1.77.


De quel sqrt. Dans <cmath>, g++ définit une fonction inline,
quelque chose du genre :
inline double sqrt( double f )
{ return __builtin_sqrt( f ) ; }
Alors, le compilateur sait de quoi il s'agit, et peut en faire
beaucoup.

Mais c'est un cas très spécial.

--
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 Mar 19, 5:18 pm, Sylvain Togni <"sylvain.togni at
visionobjects.com"> wrote:
wrote:
Par exemple:
on fixe une valeur et par la suite on a besoin de sa racine:
const float pi = 7;
float f = sqrt(pi).

Si un compilateur soit disant évolué appelle sqrt à chaque itér ation,
il est pas très malin puisque pi et sqrt sont connues au moment de la
compilation*. Je m'attend à ce que ces 2 lignes, écrites ainsi pour
assurer la lisibilité du code, soient remplacée par l'équivalent en
langage machine de
float f = 1.772004515;


Oui, peut-être que le compilateur fera l'optimisation, mais
il la fera aussi bien si la variable pi n'est pas déclarée
const.


Pas forcément. Il ne le ferait que s'il peut démontrer que la
valeur ne change jamais. Dans le cas d'un objet const, il sait
d'office que la valeur ne change jamais, puisqu'essayer de la
changer est un comportement indéfini. Donc, s'il n'y a que ces
deux lignes, oui, il y a de fortes chances que le const ne
change rien. Mais si pi est une variable globale, ou qu'on en
prend l'adresse (y compris parce qu'on l'a passé par référence),
et l'optimisation ne vaut plus.

Les compilateurs, dans la plupart des cas, savent mieux que
le programmeur quelle variable est constante et quelle ne
l'est pas.


Je ne crois pas. En ce qui concerne les variables locales dont
on ne prend jamais l'adresse, peut-être. Mais autrement,
sûrement pas.

Preuve en est, ils émettent une erreur quand
on essaie de modifier une variable const.


C'est un autre problème, qui se résoud facilement avec un
analyse parfaitement locale. Le problème, c'est que souvent, le
compilateur ne peut pas voir tous les accès à la variable, et ne
sait donc pas s'il y a une modification ou non.

--
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
Loïc Joly
Si un compilateur soit disant évolué appelle sqrt à chaque itération,
il est pas très malin puisque pi et sqrt sont connues au moment de la
compilation*.



Il le fait, en revanche. Parce que comment sait-il que sqrt(7)
renvoie toujours la même valeur ?



D'où la proposition de pouvoir déclarer des fonctions "pures" qui
permettraient ce genre d'optimisations.

--
Loïc


Avatar
James Kanze
On Mar 19, 5:22 pm, Sylvain Togni <"sylvain.togni at
visionobjects.com"> wrote:
Michel Decima wrote:
Petite précision : le mot-clé const n'a aucune incidence
sur les performances, il sert juste à éviter certains bugs
et à améliorer la lisibilité du code.


La documentation de mon compilateur (xlC-6/AIX) me dit "Use the const
qualifier whenever possible" dans la section "Coding Techniques That Can
Improve Performance".
D'un autre coté, le titre de la section dit que ca _peut_ améliorer les
choses, pas que ca le fait systématiquement.


Je ne sais pas, la seule différence que je vois c'est qu'en
utilisant const on est assez souvent amené à définir deux fois
certaines fonctions comme les getteurs, une version const et
une version non-const, ce qui augmente la taille du code et
diminue un peu la vitesse pour des raisons de localité.


Sauf que ce genre de fonctions sont prèsque toujours inline.

Un petit essai (pas très rigueureux) montre que le const fait
une différence et avec g++ et avec Sun CC sous Solaris, et avec
g++ sous Linux. Essaie donc :

double const d = 1.0009 ;
double tot1 = 1.0 ;
double tot2 = 1.0 ;
for ( int i = 0 ; i < 1000000000 ; ++ i ) {
f( d ) ;
tot1 += 2.0 * d + 1.0 ;
tot2 += 3.0 * d + 2.0 ;
}

Avec « void f( double const& ) ». Puis sans le const sur d.
Les temps sont bien différents.

--
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
Sylvain Togni
James Kanze wrote:

Un petit essai (pas très rigueureux) montre que le const fait
une différence et avec g++ et avec Sun CC sous Solaris, et avec
g++ sous Linux. Essaie donc :

double const d = 1.0009 ;
double tot1 = 1.0 ;
double tot2 = 1.0 ;
for ( int i = 0 ; i < 1000000000 ; ++ i ) {
f( d ) ;
tot1 += 2.0 * d + 1.0 ;
tot2 += 3.0 * d + 2.0 ;
}

Avec « void f( double const& ) ». Puis sans le const sur d.
Les temps sont bien différents.


C'est vrai que dans ce genre de situations le const peut
faire une différence. Mais sont-elles vraiment courantes ?
Tu passes souvent des doubles par référence constante ?

Aussi, bizarrement, j'ai essayé ce code avec 3 compilateurs
différents et jamais la version const n'a gagné.

non-const const
-------------------------------------------------------
VC6 13.8s 13.8s
VC8 2.2s 2.2s
GCC 3.4.4 cygming 10.8s 11.8s
-------------------------------------------------------

- VC6 ne fait aucune optimisation, en const comme en
non-const et génère strictement le même code assembleur.

- VC8 fait une optimisation globale (j'ai pourtant mi la
définition de f dans une unité à part), supprime l'appel
à f et pré-calcul les deux incréments, en const comme
en non-const.

- GCC pré-calcul les deux incréments seulement en const,
effectivement, mais bizarrement cela se traduit par une
vitesse moindre de la version avec const (Vive les
architectures modernes ;-).

--
Sylvain Togni

1 2 3 4