Copia de lista de inicialización? ¿Por qué esto compila?

13

Estoy usando Microsoft Visual Studio Community 2019, V16.5.2. Quiero probar la inicialización de la lista

Consulte el siguiente programa de prueba:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Esto compila sin error y advertencia. ¿Por qué?

Da un error de tiempo de ejecución: Expression: Transposed pointer range

¿Alguien puede explicar qué está pasando aquí?


Editar.

Desmonté el código y lo ejecuté en el depurador

    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  

Se bloquea en la primera llamada al constructor?

Armin Montigny
fuente
No entiendo tu edición, pero parece que quizás sea una pregunta diferente, así que ¿quizás necesites publicar una nueva pregunta?
Mooing Duck

Respuestas:

16

std::stringtiene un constructor de plantillas que construye una cadena a partir de un par de iteradores de inicio / fin. Los literales de cadena en C ++ se convierten en const char*s. Y los punteros son iteradores. Por lo tanto, la inicialización de la lista eligió el constructor de pares de inicio / fin.

Recibió un error de tiempo de ejecución porque los dos punteros en realidad no crean un rango válido, que no se puede determinar en tiempo de compilación (generalmente).

Nicol Bolas
fuente
Entiendo. El constructor de la gama. Desmonté y depuré el código. Se bloquea en la primera llamada al constructor. No entiendo <char const *,0>. ¿Alguien puede explicar esto?
Armin Montigny
Eso significa que está llamando a la template< InputIt > (InputIt first, InputIt last,...)constructora donde el parámetro de plantilla iteres const char*.... y al parecer su aplicación tiene un segundo parámetro entero por alguna razón?
Mooing Duck
@ArminMontigny: ¿Explicar qué? El desmontaje es esencialmente irrelevante. Se afirma que su código es sintácticamente válido, pero proporciona un comportamiento indefinido debido a que no pasa un rango válido de iteradores. No necesita comprender el desmontaje para comprender por qué su código no es funcional.
Nicol Bolas
8

std::string tiene una sobrecarga del constructor en forma de

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

y esto se llama porque "str1"y "str2"decae a const char*'s y const char*es un tipo de iterador aceptable.

Se bloquea porque el "rango de iterador" que pasó a la función no es válido.

NathanOliver
fuente
Gracias entendido +1. Por favor vea la edición.
Armin Montigny
7

Que utilizan el constructor con iteradores de std :: string (6.).

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

Con [ InputIt= const char*].

Entonces tienes UB ya que el rango {"str1", "str2"}no es válido.

Jarod42
fuente
Gracias entendido +1. Por favor vea la edición.
Armin Montigny