Копіювати ініціалізацію списку? Чому це компілюється?


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  

Він виходить з ладу при першому виклику конструктора?


Я не розумію вашого редагування, але це виглядає як інше питання, тож, можливо, вам потрібно написати нове запитання?
Mooing Duck

Відповіді:


16

std::stringмає конструктор шаблонів, який будує рядок із пари ітераторів початку / кінця. Рядкові букви в C ++ переходять вниз до const char*s. А покажчики - ітератори. Тому ініціалізація списку обрала конструктор пар початку / кінця.

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


Я розумію. Конструктор діапазону Я розібрав і налагодив код. Він виходить з ладу під час першого дзвінка до конструктора. Я не розумію <char const *,0>. Може хтось, будь ласка, пояснить це?
Армін Монтінні

Це означає , що це виклик template< InputIt > (InputIt first, InputIt last,...)конструктора , де параметр шаблону iterє const char*.... і , мабуть , ваша реалізація має другий цілочисельний параметр для будь - то причини?
Mooing Duck

@ArminMontigny: Поясніть, що? Розбирання по суті не має значення. Вказується, що ваш код синтаксично дійсний, але він не визначає поведінку через те, що не проходить дійсний діапазон ітераторів. Вам не потрібно розуміти розбирання, щоб зрозуміти, чому ваш код не функціональний.
Нікол Болас

8

std::string має перевантаження конструктора у вигляді

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

і це називається тому, що "str1"і "str2"занепадає до 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.