69 votes

std::string s1 {"Modern C++", 3} vs std::string s1 {str, 3}

La sortie du code suivant me perturbe :

const std::string str = "Modern C++";

std::string s1 {"Modern C++", 3};
std::string s2 {str, 3};

std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";

sortie :

S1: Mod S2: ern C++

Quelqu'un peut-il expliquer ce résultat ?

0 votes

S1 et S2 devraient être les mêmes, à moins que je ne manque quelque chose.

3 votes

Avez-vous lu la référence en std::string des constructeurs ? "Modern C++" n'est pas un std::string mais un tableau de caractères (qui est automatiquement converti en un pointeur char), et il y a un constructeur différent pour ceux-ci.

40 votes

Bien sûr. La référence vous le dirait. Et je suis sûr qu'il y a une raison incroyablement intelligente pour laquelle ils ne font pas la même chose, que le comité de la bibliothèque C++ me prouverait en utilisant une logique et un raisonnement impeccables. Et pourtant, ce n'est qu'une raison de plus - bien que minime - pour laquelle la bibliothèque standard C++ reste peu intuitive, voire frustrante, à utiliser.

66voto

0RR Points 1291

De :

https://en.cppreference.com/w/cpp/string/basic_string/basic_string

std::string s1 {"Modern C++", 3};

Utilise le constructeur suivant :

basic_string( const CharT* s,
          size_type count,
          const Allocator& alloc = Allocator() );

Il faut donc 3 caractères pour obtenir Mod .

std::string s2 {str, 3};

utilisera le constructeur suivant :

basic_string( const basic_string& other,
          size_type pos,
          const Allocator& alloc = Allocator() );

Ainsi, en prenant la corde à partir de la position 3, on obtient : ern C++ .

35voto

Yakk Points 31636

L'un d'eux appelle string(char const*, count) l'autre string(string const&, pos) .

L'un récupère les 3 premiers caractères d'un tampon, l'autre tous les caractères après le 3ème.

Cela s'explique par le fait que le C++ dispose de tampons de caractères bruts et de chaînes de caractères std. "this is not a std::string" . "this is a std string"s , std::string so_is="this"; .

std::string a plus de 30 ans et a été ajouté au langage C++ sans être suffisamment soigné (contrairement à la STL, qui a subi plus d'itérations avant d'être ajoutée).

Son interface est honnêtement trop riche, et vous pouvez rencontrer des problèmes de ce genre ; de multiples surcharges qui mènent à des résultats confus.

7voto

einpoklum Points 2893

Quelqu'un peut-il m'expliquer pourquoi ?

Cela est dû à std::string ayant des constructeurs qu'il ne devrait pas avoir (@ORR a expliqué les détails). Et il ne devrait pas avoir ces constructeurs parce que :

  1. Leur effet est facilement réalisable en utilisant idiomes de constructeurs nommés / std::string et les constructeurs existants - sans coût supplémentaire (en C++11 au moins), et
  2. Il n'est pas évident et trivial de comprendre comment les arguments du constructeur sont utilisés en regardant simplement l'invocation du constructeur.

Ce n'est pas le seul cas dans la bibliothèque standard avec de tels constructeurs indésirables (IMHO) ; std::vector est (in)célèbre pour trop de variété de constructeurs et une sémantique de constructeur confuse ou trompeuse.

Des leçons de vie :

  • Ne lésinez pas sur les constructeurs ; tous les groupes de valeurs couramment utilisés pour construire un objet de votre classe ne méritent pas leur propre constructeur ;
  • à la place, utilisez idiomes de constructeurs nommés .
  • Demandez à votre réviseur de code ou à une autre partie moins biaisée de lire une invocation de vos constructeurs, afin d'évaluer si la signification de chacun d'eux est suffisamment évidente.

3voto

kelly43 Points 41

Au cas où vous voudriez obtenir le même résultat comme

Mod pour s1

Mod pour s2

Vous pouvez utiliser un pointeur de caractère pour str par exemple

char * str = "Modern C++";

std::string s1 {"Modern C++", 3};
std::string s2 {str, 3};

std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";

Le résultat

 Mod

 Mod

0 votes

Pour que cela fonctionne, la première ligne devrait être : char str[] = "Modern C++" ; ou char str[] {"Modern C++"} ;

0 votes

Essayez-le, pour moi cela a bien fonctionné. En c++/c vous pouvez aussi déclarer et initialiser un tableau de caractères avec un pointeur. char * str = "Modern C++" ; utilisez str[value] pour boucler parce que str est maintenant un tableau.

0 votes

Je crois que la syntaxe sans [ ] est char ** str.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X