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


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*является приемлемым типом итератора.

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


Спасибо, понял. +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"}недействителен.


Спасибо, понял. +1. Пожалуйста, смотрите редактирование.
Армин Монтиньи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.