Копировать список инициализации? Почему это компилируется?

13

Я использую Microsoft Visual Studio Community 2019, V16.5.2. Я хочу проверить инициализацию списка

Пожалуйста, смотрите следующую тестовую программу:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Это компилируется без ошибок и предупреждений. Почему?

Это дает ошибку во время выполнения: Expression: Transposed pointer range

Может кто-нибудь объяснить, что здесь происходит?


Редактировать.

Я разобрал код и запустил его в отладчике

    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  

Вылетает ли при первом вызове конструктора?

Армин Монтиньи
источник
Я не понимаю ваших правок, но похоже, что это другой вопрос, так что, возможно, вам нужно опубликовать новый вопрос для него?
Утка

Ответы:

16

std::stringимеет шаблонный конструктор, который строит строку из пары итератор начала / конца. Строковые литералы в C ++ переходят в const char*s. И указатели являются итераторами. Поэтому при инициализации списка был выбран начальный / конечный пары конструктор.

Вы получили ошибку во время выполнения, потому что два указателя фактически не создают допустимый диапазон, который не может быть определен во время компиляции (как правило).

Николь Болас
источник
Я понимаю. Конструктор диапазона. Я разобрал и отладил код. Вылетает при первом вызове конструктора. Я не понимаю <char const *,0>. Может кто-нибудь, пожалуйста, объясните это?
Армин Монтиньи
Это означает , что это вызов template< InputIt > (InputIt first, InputIt last,...)конструктора , где параметр шаблона iterявляется const char*.... и , видимо , ваша реализация имеет второй целочисленный параметр для какой - то причины?
Мычанка
@ArminMontigny: объясни что? Разборка по сути не имеет значения. Ваш код считается синтаксически допустимым, но он дает неопределенное поведение из-за того, что не прошел допустимый диапазон итераторов. Вам не нужно разбираться в разборке, чтобы понять, почему ваш код не работает.
Никол Болас
8

std::string имеет перегрузку конструктора в виде

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

и это вызывается потому что "str1"и "str2"decay to const char*s и const char*является приемлемым типом итератора.

Вы получаете сбой, потому что «диапазон итераторов», который вы передали функции, недопустим.

NathanOliver
источник
Спасибо, понял. +1. Пожалуйста, смотрите редактирование.
Армин Монтиньи
7

Это использовать конструктор с итераторами std :: string (6.).

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

С помощью [ InputIt= const char*].

Тогда у вас есть UB, поскольку диапазон {"str1", "str2"}недействителен.

Jarod42
источник
Спасибо, понял. +1. Пожалуйста, смотрите редактирование.
Армин Монтиньи