Salin Inisialisasi Daftar? Mengapa ini dikompilasi?

13

Saya menggunakan Microsoft Visual Studio Community 2019, V16.5.2. Saya ingin menguji inisialisasi daftar

Silakan lihat program tes berikut:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Ini mengkompilasi tanpa kesalahan dan peringatan. Mengapa?

Ini memberikan kesalahan runtime: Expression: Transposed pointer range

Adakah yang bisa menjelaskan apa yang terjadi di sini?


Edit.

Saya membongkar kode dan menjalankannya di debugger

    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  

Itu crash pada panggilan pertama ke konstruktor?

Armin Montigny
sumber
Saya tidak mengerti hasil edit Anda, tetapi sepertinya pertanyaan yang berbeda, jadi mungkin Anda perlu mengirim pertanyaan baru untuk itu?
Mooing Duck

Jawaban:

16

std::stringmemiliki konstruktor template yang membangun string dari pasangan iterator begin / end. String literal di C ++ berpindah ke const char*s. Dan pointer adalah iterator. Oleh karena itu, inisialisasi daftar memilih konstruktor pasangan mulai / akhir.

Anda mendapat kesalahan runtime karena kedua pointer tidak benar-benar membuat rentang yang valid, yang tidak dapat ditentukan pada waktu kompilasi (umumnya).

Nicol Bolas
sumber
Saya mengerti. Konstruktor rentang. Saya membongkar dan men-debug kode. Itu crash dalam panggilan pertama ke konstruktor. Saya tidak mengerti <char const *,0>. Bisakah seseorang tolong jelaskan ini?
Armin Montigny
Itu artinya memanggil template< InputIt > (InputIt first, InputIt last,...)konstruktor di mana parameter templat iteradalah const char*.... dan ternyata implementasi Anda memiliki parameter integer kedua karena alasan tertentu?
Mooing Duck
@ArminMontigny: Jelaskan apa? Pembongkaran pada dasarnya tidak relevan. Kode Anda dinyatakan valid secara sintaksis tetapi memberikan perilaku yang tidak terdefinisi karena tidak melewati kisaran iterator yang valid. Anda tidak perlu memahami pembongkaran untuk memahami mengapa kode Anda tidak berfungsi.
Nicol Bolas
8

std::string memiliki kelebihan konstruktor dalam bentuk

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

dan ini dipanggil karena "str1"dan "str2"meluruh ke const char*dan const char*merupakan jenis iterator yang dapat diterima.

Anda mendapatkan crash karena "rentang iterator" yang Anda berikan ke fungsi tidak valid.

NathanOliver
sumber
Terima kasih, mengerti. +1. Silakan lihat hasil edit.
Armin Montigny
7

Itu menggunakan konstruktor dengan iterators dari std :: string (6.).

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

Dengan [ InputIt= const char*].

Maka Anda memiliki UB karena rentang {"str1", "str2"}tidak valid.

Jarod42
sumber
Terima kasih, mengerti. +1. Silakan lihat hasil edit.
Armin Montigny