Inizializzazione elenco copie? Perché questa compilazione?


13

Sto usando Microsoft Visual Studio Community 2019, V16.5.2. Voglio testare l' inizializzazione dell'elenco

Si prega di consultare il seguente programma di test:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Questo viene compilato senza errori e avvisi. Perché?

Dà un errore di runtime: Expression: Transposed pointer range

Qualcuno può spiegare cosa sta succedendo qui?


Modificare.

Ho smontato il codice ed eseguito nel debugger

    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  

Si blocca alla prima chiamata al costruttore?


Non capisco la tua modifica, ma sembra forse una domanda diversa, quindi forse devi pubblicare una nuova domanda per questo?
Mooing Duck

Risposte:


16

std::stringha un costruttore di template che costruisce una stringa da una coppia di iteratori di inizio / fine. I letterali di stringa in C ++ si riducono a const char*s. E i puntatori sono iteratori. Pertanto, l'inizializzazione dell'elenco ha scelto il costruttore della coppia inizio / fine.

Si è verificato un errore di runtime perché i due puntatori non creano effettivamente un intervallo valido, che non può essere determinato in fase di compilazione (in genere).


Capisco. Il costruttore della gamma. Ho smontato ed eseguito il debug del codice. Si arresta in modo anomalo durante la prima chiamata al costruttore. Non capisco <char const *,0>. Qualcuno può spiegare questo?
Armin Montigny,

Ciò significa che è chiamare il template< InputIt > (InputIt first, InputIt last,...)costruttore dove il parametro di template iterè const char*.... e apparentemente l'implementazione ha un secondo parametro intero per qualche motivo?
Mooing Duck

@ArminMontigny: spiega cosa? Lo smontaggio è essenzialmente irrilevante. Il tuo codice è dichiarato sintatticamente valido ma fornisce un comportamento indefinito a causa del mancato passaggio di un intervallo valido di iteratori. Non è necessario comprendere lo smontaggio per capire perché il codice non è funzionale.
Nicol Bolas,

8

std::string ha un sovraccarico del costruttore sotto forma di

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

e questo viene chiamato perché "str1"e "str2"decade a const char*'s ed const char*è un tipo iteratore accettabile.

Si verifica un arresto anomalo perché "l'intervallo dell'iteratore" passato alla funzione non è valido.


Grazie capito. +1. Si prega di vedere la modifica.
Armin Montigny,

7

Che usano il costruttore con iteratori di std :: string (6.).

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

Con [ InputIt= const char*].

Quindi hai UB poiché l'intervallo {"str1", "str2"}non è valido.


Grazie capito. +1. Si prega di vedere la modifica.
Armin Montigny,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.