คัดลอกการเริ่มต้นรายการหรือไม่ ทำไมคอมไพล์นี้?


13

ฉันใช้ Microsoft Visual Studio Community 2019, V16.5.2 ฉันต้องการทดสอบการเริ่มต้นรายการ

โปรดดูโปรแกรมทดสอบต่อไปนี้:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

คอมไพล์โดยไม่มีข้อผิดพลาดและคำเตือน ทำไม?

มันให้ข้อผิดพลาด runtime: 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>ฉันไม่เข้าใจ ใครช่วยอธิบายได้ไหม
Armin Montigny

นั่นหมายความว่ามันกำลังเรียกคอนtemplate< InputIt > (InputIt first, InputIt last,...)สตรัคเตอร์ว่าพารามิเตอร์เทมเพลตiterคือconst char*.... และเห็นได้ชัดว่าการใช้งานของคุณมีพารามิเตอร์จำนวนเต็มที่สองด้วยเหตุผลบางอย่าง?
Mooing Duck

@ArminMontigny: อธิบายอะไร การถอดแยกชิ้นส่วนนั้นไม่เกี่ยวข้อง รหัสของคุณระบุว่าถูกต้องทางไวยากรณ์ แต่มีพฤติกรรมที่ไม่ได้กำหนดเนื่องจากไม่ผ่านช่วงของตัววนซ้ำที่ถูกต้อง คุณไม่จำเป็นต้องเข้าใจการถอดแยกชิ้นส่วนเพื่อทำความเข้าใจว่าทำไมรหัสของคุณถึงไม่สามารถใช้งานได้
Nicol Bolas

8

std::string มีตัวสร้างเกินพิกัดในรูปแบบของ

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

และสิ่งนี้ได้รับการเรียกเพราะ"str1"และ "str2"สลายตัวไปconst char*และconst char*เป็นประเภทตัววนซ้ำที่ยอมรับได้

คุณได้รับความผิดพลาดเนื่องจาก "ช่วงตัววนซ้ำ" ที่คุณส่งไปยังฟังก์ชันไม่ถูกต้อง


ขอบคุณเข้าใจ +1 โปรดดูการแก้ไข
Armin Montigny

7

ที่ใช้นวกรรมิกกับ iterators ของstd :: string (6. )

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

ด้วย [ InputIt= const char*]

จากนั้นคุณมี UB เนื่องจากช่วง{"str1", "str2"}ไม่ถูกต้อง


ขอบคุณเข้าใจ +1 โปรดดูการแก้ไข
Armin Montigny
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.