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?


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).


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.


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.


Terima kasih, mengerti. +1. Silakan lihat hasil edit.
Armin Montigny
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.