Sao chép danh sách khởi tạo? Tại sao điều này biên dịch?


13

Tôi đang sử dụng Microsoft Visual Studio Community 2019, V16.5.2. Tôi muốn kiểm tra khởi tạo danh sách

Vui lòng xem chương trình kiểm tra sau:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

Điều này biên dịch mà không có lỗi và cảnh báo. Tại sao?

Nó đưa ra một lỗi thời gian chạy: Expression: Transposed pointer range

Ai đó có thể vui lòng giải thích những gì đang xảy ra ở đây?


Biên tập.

Tôi đã gỡ bỏ mã và chạy nó trong trình gỡ lỗi

    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  

Nó gặp sự cố ở cuộc gọi đầu tiên đến nhà xây dựng?


Tôi không hiểu bản chỉnh sửa của bạn, nhưng có vẻ như có thể là một câu hỏi khác, vì vậy có lẽ bạn cần đăng một câu hỏi mới cho nó?
Vịt Mooing

Câu trả lời:


16

std::stringcó một hàm tạo mẫu xây dựng một chuỗi từ một cặp vòng lặp bắt đầu / kết thúc. Chuỗi ký tự trong C ++ chuyển thành const char*s. Và con trỏ là các vòng lặp. Do đó, khởi tạo danh sách đã chọn hàm tạo cặp bắt đầu / kết thúc.

Bạn gặp lỗi thời gian chạy vì hai con trỏ không thực sự tạo ra một phạm vi hợp lệ, không thể xác định được tại thời gian biên dịch (nói chung).


Tôi hiểu. Các nhà xây dựng phạm vi. Tôi đã tháo rời và gỡ lỗi mã. Nó gặp sự cố trong cuộc gọi đầu tiên đến hàm tạo. Tôi không hiểu <char const *,0>. Ai đó có thể vui lòng giải thích điều này?
Armin Montigny

Điều đó có nghĩa là nó đang gọi hàm template< InputIt > (InputIt first, InputIt last,...)tạo trong đó tham số mẫu iterconst char*.... và rõ ràng việc triển khai của bạn có tham số nguyên thứ hai vì một số lý do?
Vịt Mooing

@ArminMontigny: Giải thích cái gì? Việc tháo gỡ về cơ bản là không liên quan. Mã của bạn được tuyên bố là hợp lệ về mặt cú pháp nhưng nó mang lại hành vi không xác định do không vượt qua một phạm vi lặp hợp lệ. Bạn không cần phải hiểu việc tháo gỡ để hiểu lý do tại sao mã của bạn không hoạt động.
Nicol Bolas

8

std::string có một quá tải xây dựng ở dạng

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

và điều này được gọi bởi vì "str1""str2"phân rã thành const char*'và const char*là một kiểu vòng lặp chấp nhận được.

Bạn gặp sự cố vì "phạm vi lặp" mà bạn chuyển đến hàm không hợp lệ.


Cảm ơn, đã hiểu. +1. Xin vui lòng xem chỉnh sửa.
Armin Montigny

7

Điều đó sử dụng hàm tạo với các trình lặp của std :: string (6.).

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

Với [ InputIt= const char*].

Sau đó, bạn có UB là phạm vi {"str1", "str2"}không hợp lệ.


Cảm ơn, đã hiểu. +1. Xin vui lòng xem chỉnh sửa.
Armin Montigny
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.