Au contraire, j’ai utilisé \n parce que je voulais éviter std::endl. Ici je veux juste faire un retour à la ligne, ni plus ni moins, donc \n est parfaitement adapté.
Sur stdout, en général std::endl et \n ont le même effet (vu que, par défaut, stdout est souvent bufferisé par ligne) donc oui c’est vraiment une histoire de préférence personnelle que d’utiliser l’un ou l’autre.
En revanche, sur un fichier on risque de sentir une différence (flusher le buffer à chaque ligne c’est pas terrible niveau perf’)
Ma remarque était dans le cadre d'une réponse à une question de débutant. Les deux méthodes étant à peu près identiques, il est conseillé d'utiliser la méthode la plus standard, à savoir celle qui utilise la lib standard du c++.
ça dépend le but recherché. Si tu veux faire un logger ou n'importe quel type d'output que tu souhaites pouvoir vérifier en temps réel, alors tu n'as pas le choix. Et de façon générale, ne pas flusher systématiquement pose de nombreux problèmes de robustesse: il est difficile de contrôler le chemin d'exécution si on ne sait pas où ça flushe. Et il y a le problème du multithreading.
D'une façon générale, il faut préférer le endl. Et si jamais cela pose des problèmes de performance au runtime, alors la question de remplacer par des '\n' pourra se poser, mais seulement après.
'\n' c’est autant du C++ standard que std::endl…
Par contre, les deux ont des sémantiques différentes oui : l’un est le moyen standard de faire un retour à la ligne, l’autre est le moyen standard de faire un retour à la ligne + flush.
Oui, tout à fait.
Dans ce cas-là c’est pleinement justifié.
Rien n’empêche de faire des appels à std::flush à des « points de contrôle ». Comme ça tu sais exactement où ça flushe.
Après tout dépend de l’application (oui un logger doit flusher à chaque ligne donc std::endl est parfait), mais il peut aussi y avoir un juste milieu entre ne jamais flusher (laisser le système gérer) et flusher à chaque ligne.
Hum, en général si tu as plusieurs threads qui veulent écrirent en même temps sur le même flux tu vas protéger l’accès par un mutex, flush ou pas.
Le flush ne va pas te protéger de l’entrelacement pour ce que j’en sais.
Personnellement, j’ai plutôt l’approche inverse.
Par défaut, on va au plus simple : simple retour à la ligne.
Après, si besoin il y a ou cas particulier (le logger était un très bon exemple), on ajoute des flush (ou usage de std::endl).
Mais, ça reste un détail.
Non, endl prend en compte les différences entre système d'exploitation, les encodages, etc. Par exemple, dans certains encodages, un retour charriot d'un fichier est '\r\n'. endl gère tout ça.
En gros, pourquoi faire simple quand on peut faire compliqué?
Pour le MT, utiliser endl te permet au moins de ne protéger que tes accès en écriture. Si tu utilises '\n', il faut que tu gère les accès concurrents à tous les niveaux, ça peut vite devenir ingérable.
Sauf que le plus simple c'est le endl, c'est pas le '\n'. De même que le plus simple c'est la classe string, pas le char*.
C'est un détail, mais si cette discussion revient régulièrement c'est parce qu'elle cristallise deux visions du c++. Une vision qui conçoit le c++ en tant qu'amélioration du C, et une autre vision, qui est la mienne, qui prend le c++ comme un langage à part entière, et dont la stl est la brique de base, dont il faut abuser.
Ça c’est un mythe. \n a exactement le même effet au niveau de l’encodage de la fin de ligne. C’est tout aussi portable.
Et tu sais pourquoi ?
Parce std::endl ne fait rien de plus que d’écrire \n dans le flux puis il appelle std::flush. Il y a bien un appel à os.widen mais ça n’a rien à voire avec les histoire de \n, \r ou \r\n…
Je t’invite à faire le test (ou à lire la section 27.7.3.8 du standard).
Là je ne vois pas de quoi tu parles.Envoyé par r0d
flush ou pas, si deux threads joue en même temps sur le même flux tu risques des soucis.
Tu peux me donner un exemple s’il te plaît ? Ça sera peut-être plus clair.
Je suis d‘accord pour std::string vs char*, par contre pas pour std::endl vs \n.Envoyé par r0d
Pour moi il n’est pas plus simple, il joue un autre rôle.
Moi aussi j’ai cette vision et je lutte contre ceux qui font du C-with-classes ou un sabir C/C++.Envoyé par r0d
Mais là, à t’entendre on dirait que \n ce n’est pas du C++, mais du C. Et je trouve ça un peu fort.
Moi aussi je suis pour utiliser à fond la STL, quand c’est justifié. Mais je pense aussi que quand \n remplit son rôle autant l’utiliser (surtout qu’il est tout aussi portable que std::endl comme je l’ai montré plus haut).
Je n'ai malheureusement pas la norme sous la main. Et peut-être que cette histoire de '\r\n' est un mythe, mais je sais que j'ai eu des soucis avec ça quand j'étais débutant. Bon à l'époque je ne comprenais pas grand chose au c++, alors j'ai sans doute mal compris le problème. Mais quoi qu'il en soit, comme tu l'as noté, il y a cet appel à widen qui normalise l'encodage.
Je ne trouve pas d'exemple, tu as peut-être raison en fait.
Mais si on oublie le MT, il me parait tout de même nettement plus compliqué de chercher les endroits corrects pour flusher son buffer, sans parler des problèmes potentiels de maintenance, plutôt que de le faire systématiquement.
Je l'ai dit de façon un peu abrupte, et je m'en excuse, mais ce que je veux dire, c'est que dans 99% des cas, les quelques cycles qu'on va gagner en n'utilisant pas la STL n'en valent pas la peine. Par exemple, si tu veux faire un tableau de 3 entiers, tu vas gagner probablement quelques cycles en utilisant un int[3] plutôt qu'un vector<int> (et encore c'est pas sûr), mais dans 99% des cas, ce gain de perf est dérisoire et même si la performance est une contrainte critique (ce qui est assez rare dans la vrai vie), cette différence n'apparaitra même pas au profiling.
En fait, tant que que le flux est en mode texte, le \n est interprété comme il faut pour la plateforme sous-jacente.
Par contre, c’est vrai que l’on profite automatiquement du widen en utilisant std::endl.
Cela dit, je ne sais pas si on y gagne tant que ça, car de toutes façons pour écrire autre chose que de l’ASCII il faut passer par std::wcout (donc un changement explicite à faire) il me semble, donc std::endl ne fait pas tout. Mais oui, sur ce coup-là c’est plus pratique qu’un \n nu, c’est vrai.
Oui, si on veut flusher c’est plus simple de le faire partout qu’au cas pas cas. C’est sûr.
Mais j’ai vraiment vu de nombreux témoignages sur le fait que utiliser std::endl de manière systématique lorsque l’on bosse avec un fichier diminuait les performances de manière non négligeable (un facteur 2 ou plus n’étant pas rare, sauf si c’est pour écrire 4 lignes bien sûr).
Bon, après peut-être que ces témoignages datent un peu et que maintenant c’est beaucoup moins pénalisant. Dans tout les cas c’est à voir au cas pas cas, selon l’application (contrainte de vitesse, robustesse, etc.). Pas de règle absolue.
Tout à fait d’accord.Envoyé par r0d
Et on gagne toujours plus à optimiser son algorithme qu’a remplacer des std::string par des char* (et je ne parle même pas de la clarté du code, du risque de bug en moins et du temps gagné en développement).
Et puis depuis le C++11, avec std::array ce n’est même pas sûr que l’on y gagne encore quoique ce soitEnvoyé par r0d
Mais je suis d’accord avec ton exemple.
Bonjour,
j'ai splité les messages depuis la discussion d'origine.
Inutile de géner un débutant avec de tels considérations, vous pouvez continuer votre débat/battle (débattle ?!) ici![]()
Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
Un peu de programmation réseau ?
Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.
Yep, t'as raison Bousk, on va faire fuir nos débutants avec cestrollsdébats sans fin
Mais je reste convaincu qu'il vaut mieux enseigner aux débutants d'utiliser systématiquement endl à la place de '\n'.
Non, je lâche rien!![]()
Le découpage est le bienvenue.
C’est vrai que l’on commençait à être sérieusement HS ^^"
Moi je pense qu’il faut leur enseigner les deux, pour qu’ensuite ils puissent choisir en connaissance de cause.
Personnellement le trouve l’entrée de la FAQ plutôt bien faire : elle est courte (pas comme nos messages à rallong qui effraie les débutants) et explique la différence.
Après, une fois informé chacun prend sa décision en connaissance de cause.
Salut,
J'ai toujours eu pour principe d'avoir, dans l'ordre:
Si je mets les choses dans cet ordre, c'est parce qu'il est beaucoup plus facile, au niveau de la maintenance de corriger un code bien écrit, surtout s'il est lent qu'un code qui arrive rapidement au plantage
- un code compréhensible par celui qui pose les yeux dessus
- un code qui fait ce qu'on lui demande
- un code qui fait rapidement ce qu'on lui demande
Et, personnellement, j'ai tendance à estimer qu'il est "si facile" de passer à coté d'un '\n', surtout s'il est bien encadré, que std::endl a, au moins, le mérite d'être beaucoup plus visible.
D'autant plus que, je ne sais pas vous, mais, d'habitude, je vais à la ligne (au niveau du code) après std::endl, plus rarement après un '\n'
Enfin, je crois qu'avant de commencer à s'inquiéter d'un flush peut etre intempestif, il y a le plus souvent énormément à faire au niveau des algorithmes et de la logique en générale et que, une fois que ce travail là est fait, il y a très certainement d'autres moyens à aborder, comme le fait d'éviter les cache miss, avant de s'inquiéter de savoir si l'on gagne deux cycles en utilisant '\n'.
Je ne vais pas rentrer d'avantage dans le débat, car je suis sur ce coup en total accord avec r0d, mais je tenais malgré tout à vous faire profiter de mon opinion personnelle... mais que je partage![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
La dernière version de C++ Primer conseille effectivement d'utiliser \n dans le cas d'une écriture vers des fichiers.
Par ailleurs, selon moi, les tableaux ne doivent être remplacés par des vecteurs que si la taille n'est pas connue à la compilation.
Ces défauts dépendent de comment tu présentes ton code.
Après, je ne cherche pas à imposer l’usage de \n partout au lieu de std::endl.
Pour moi ce sont juste deux choses différentes qui ont des usages différents (mais proche), du coup personnellement je me pose rarement la question d’utiliser l’un ou l’autre car les cas d’usage sont différents (comme puts et printf en C).
Sur un truc un avec des I/O un tant soit peu conséquente, il y’a bien plus de 2 cycles à gagner entre un flush à chaque ligne ou pas…
Un flush ça implique un accès disque ce qui est très lent, la bufferisation permet d’écrire en RAM et de grouper les accès disque donc forcément l’écart n’est pas que de deux cycles (ou alors c’est encore mieux qu’un SSD ce que tu as).
Mis à part ce détail, je suis totalement d’accord que l’on a plus à gagner en soignant les algorithmes et la logique de haut niveau. C’est certain (je le disais d’ailleurs dans un message précédent).
Mais j’ai l’impression que tu sous-estime quand même un peu le coût d’un flush. Pour moi c’est de même niveau que les caches miss (après je ne connais pas les rapports temps d’accès cache/RAM et RAM/disque), si ce n’est que c’est moins fréquent (les flush ne concernent que les I/O, les cache miss c’est plus global donc oui il vaut mieux les optimiser en premier).
Oui, sinon il vaut mieux utiliser les std::array (C++11) ou std::dynarray (C++14)
Je suis derrière grim7reaper sur l'histoire.
- endl ne protège en rien contre les accès concurrents. Mais alors rien du tout. cout est une variable globale, et les << de chaque thread peuvent s'entrelacer (et même à l'intérieur du code des <<, il peut y avoir des entrelacements). Pour s'en sortir, il faut remplacer le streambuf de cout par un streambuf qui contient un ensemble de streambufs (un par thread ; par TLS/TSS ou autre moyen), et flusher le streambuf du thread courant sur un flush.
- endl, ce n'est jamais que \n + flush (sur cout, sur wcout, bien évidemment, c'est autre chose, mais vu que la chaine littérale que l'on écrit sera adaptée, le \n aussi, IIRC)
- et \n en mode non binaire sera adapté en ce qui va bien pour le couple OS/compilo
Quand à mon code, je préfère aujourd'hui employer \n qui est bien plus concis, et tout aussi clair pour tout ceux qui font du C, du bash, du perl, ...
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Après un rapide test : écriture d'~1 millions de lignes (2^20) dans un fichierÇa donne une idée (au moins un ordre de grandeur) du coût de std::endl.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 // lignes de 1 caractère (3Mo au total) std::endl 1413.08ms '\n': 111.006ms // lignes de 1024 caractères (~1Go au total) std::endl 4084.23ms '\n': 3018.17ms
@lmghs: il me semble justement que pour les buffers synchronisés (comme std::cout), chaque << doit être thread-safe d'après ce que j'en lis sur cppreference, et atomique de ce que j'ai pu observer de mes nombreux tests :
Envoyé par cppreference
C’est garanti, oui tu raison :
Mais comme précisé, il y a toujours besoin de synchro’ pour éviter l’entrelacement.Envoyé par ISO/IEC N3242 §27.4.14
Du coup, std::endl n’aide absolument en rien à ce niveau-là.
Au temps pour moi alors.
BTW, tu peux dire Luc ici![]()
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Oups, l'habitude.
Même si ce n'est pas garanti par le standard visiblement (d'après la note ?), je n'ai jamais eu d'entrelacement de caractères :
Peut donner :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 //thread1 std::cout << "bonjour" << "bonsoir"; //thread2 std::cout << "ohayo" << "konbanwa";
Mais pas plus mélangé que ça.bonjourohayobonsoirkonbanwa
Partager