Inicialização da lista de cópias? Por que isso compila?


13

Estou usando a Comunidade do Microsoft Visual Studio 2019, V16.5.2. Quero testar a inicialização da lista

Por favor, veja o seguinte programa de teste:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Isso compila sem erro e aviso. Por quê?

Dá um erro de tempo de execução: Expression: Transposed pointer range

Alguém pode explicar o que está acontecendo aqui?


Editar.

Desmontei o código e o executei no 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  

Falha na primeira chamada para o construtor?


Não entendo sua edição, mas parece que talvez seja uma pergunta diferente; talvez você precise postar uma nova pergunta para ela?
Mooing Duck

Respostas:


16

std::stringpossui um construtor de modelo que cria uma cadeia de caracteres a partir de um par de iterador de início / fim. Literais de string em C ++ são reduzidos para const char*s. E ponteiros são iteradores. Portanto, a inicialização da lista escolheu o construtor de pares de início / fim.

Você obteve um erro de tempo de execução porque os dois ponteiros não criam realmente um intervalo válido, que não pode ser determinado em tempo de compilação (geralmente).


Compreendo. O construtor de intervalo. Desmontei e depurei o código. Falha na primeira chamada ao construtor. Eu não entendo <char const *,0>. Alguém pode explicar isso?
Armin Montigny

Isso significa que ele está chamando o template< InputIt > (InputIt first, InputIt last,...)construtor onde o parâmetro do modelo iteré const char*.... e, aparentemente, sua implementação tem um segundo parâmetro inteiro por algum motivo?
Mooing Duck

@ArminMontigny: Explique o que? A desmontagem é essencialmente irrelevante. Seu código é declarado sintaticamente válido, mas oferece um comportamento indefinido devido à não aprovação de um intervalo válido de iteradores. Você não precisa entender a desmontagem para entender por que seu código não é funcional.
Nicol Bolas 03/04

8

std::string tem uma sobrecarga de construtor na forma de

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

e isso é chamado porque "str1"e "str2"decadência para const char*'s e const char*é um tipo de iterador aceitável.

Você sofre uma falha porque o "intervalo do iterador" que você passou para a função é inválido.


Obrigado, entendido. +1. Por favor, veja a edição.
Armin Montigny

7

Que usam o construtor com iteradores de std :: string (6.).

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

Com [ InputIt= const char*].

Então você tem UB, pois o intervalo {"str1", "str2"}é inválido.


Obrigado, entendido. +1. Por favor, veja a edição.
Armin Montigny
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.