Copier l'initialisation de la liste? Pourquoi cela compile-t-il?

13

J'utilise Microsoft Visual Studio Community 2019, V16.5.2. Je veux tester initialisation de la liste

Veuillez consulter le programme de test suivant:

#include <string>

void foo(std::string str) {}

int main() {

    foo( {"str1", "str2"} );

    return 0;
}

Cela se compile sans erreur et sans avertissement. Pourquoi?

Il donne une erreur d'exécution: Expression: Transposed pointer range

Quelqu'un peut-il expliquer ce qui se passe ici?


Éditer.

J'ai démonté le code et l'ai exécuté dans le débogueur

    foo( {"str1", "str2"} );
00F739A8  sub         esp,1Ch  
00F739AB  mov         esi,esp  
00F739AD  mov         dword ptr [ebp-0C8h],esp  
00F739B3  lea         ecx,[ebp-0D1h]  
00F739B9  call        std::allocator<char>::allocator<char> (0F7136Bh)  
00F739BE  push        eax  
00F739BF  push        offset string "str2" (0F84DB8h)  
00F739C4  push        offset string "str1" (0F84E2Ch)  
00F739C9  mov         ecx,esi  
00F739CB  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> ><char const *,0> (0F71569h)  
00F739D0  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0F71843h)  
00F739D5  add         esp,1Ch  

Ça plante au premier appel au constructeur?

Armin Montigny
la source
Je ne comprends pas votre montage, mais cela ressemble peut-être à une question différente, alors peut-être que vous devez poster une nouvelle question pour cela?
Mooing Duck

Réponses:

16

std::stringa un constructeur de modèle qui construit une chaîne à partir d'une paire d'itérateurs de début / fin. Les littéraux de chaîne en C ++ reviennent à const char*s. Et les pointeurs sont des itérateurs. Par conséquent, l'initialisation de la liste a choisi le constructeur de paire de début / fin.

Vous avez obtenu une erreur d'exécution car les deux pointeurs ne créent pas réellement une plage valide, qui ne peut pas être déterminée au moment de la compilation (généralement).

Nicol Bolas
la source
Je comprends. Le constructeur de la gamme. J'ai démonté et débogué le code. Il se bloque lors du premier appel au constructeur. Je ne comprends pas <char const *,0>. Quelqu'un peut-il expliquer cela?
Armin Montigny
Cela signifie qu'il appelle le template< InputIt > (InputIt first, InputIt last,...)constructeur où le paramètre de modèle iterest const char*.... et apparemment, votre implémentation a un deuxième paramètre entier pour une raison quelconque?
Mooing Duck
@ArminMontigny: Expliquez quoi? Le démontage est essentiellement hors de propos. Votre code est déclaré syntaxiquement valide mais il donne un comportement indéfini car il ne passe pas une plage valide d'itérateurs. Vous n'avez pas besoin de comprendre le démontage pour comprendre pourquoi votre code n'est pas fonctionnel.
Nicol Bolas
8

std::string a une surcharge de constructeur sous la forme de

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

et cela s'appelle parce que "str1"et "str2"pourrirconst char* et const char*est un type d'itérateur acceptable.

Vous obtenez un plantage car la "plage d'itérateurs" que vous avez transmise à la fonction n'est pas valide.

NathanOliver
la source
Merci, compris. +1. Veuillez voir la modification.
Armin Montigny
7

Cela utilise le constructeur avec les itérateurs de std :: string (6.).

template< class InputIt >
constexpr basic_string( InputIt first, InputIt last,
                        const Allocator& alloc = Allocator() );

Avec [InputIt =const char* ].

Ensuite, vous avez UB car la plage {"str1", "str2"}n'est pas valide.

Jarod42
la source
Merci, compris. +1. Veuillez voir la modification.
Armin Montigny