การเปรียบเทียบ std::string_view และสตริงย่อย string_view

สมมติว่าเรามี string_view และ string_view อีกอันที่เป็นส่วนย่อยของ string_view แรก:

using namespace std; // just to shorten the example...

string_view s{"abc def"};
auto t = s.substr(4);
auto u = s.substr(0, 4);

cout << *(s.begin() + 4) << "  " << *t.begin() << '\n';
cout << ((s.begin() + 4) == t.begin());
cout << (s.end() == t.end());
cout << ((s.begin() +5) == t.begin());
cout << ((s.begin() +5) == (t.begin() + 1));
cout << ((s.begin() + 4) == u.end()); // true

การเปรียบเทียบทั้งหมดจะทำงานบน Linux ภายใต้ gcc (9 HEAD) และ clang (8 HEAD) ภายใต้ Windows Visual c++ (15.7.6) ไม่อนุญาตให้ทำการเปรียบเทียบตัววนซ้ำสองตัว (ในโหมดแก้ไขข้อบกพร่องคุณจะได้รับข้อผิดพลาดในการยืนยัน cannot compare incompatible string_view iterators for equality)

ถัดไปคือการเปรียบเทียบตัวชี้:

string_view s{"abc def"};
char const*& it{...}; // contains pointer to some location in s
auto t = s.substr(4);

it == s.end(); // works in gcc/clang - fails to compile in Visual studio

ดังนั้นเมื่อคุณพยายามแก้ไขใน Visual C++ คุณต้องการเปรียบเทียบที่อยู่ it == &*s.end() แต่สิ่งนี้ล้มเหลวเนื่องจากตัววนซ้ำ end() ไม่ควรถูกยกเลิกการอ้างอิง (UB ถ้าฉันจำได้อย่างถูกต้อง) ดังนั้นคุณจะได้รับ cannot dereference end string_view iterator

boost::string_view รองรับการเปรียบเทียบ it == s.end() ดังนั้นฉันจึงแปลกใจที่การใช้งาน std นั้นมีข้อ จำกัด มากกว่า (และด้วยเหตุนี้จึงเป็นมิตรกับผู้ใช้น้อยกว่ามากสำหรับงานข้ามแพลตฟอร์ม)

ฉันเข้าใจว่าการเปรียบเทียบตัววนซ้ำของสองคอนเทนเนอร์ที่แตกต่างกันคือ UB แต่ string_view ไม่ใช่คอนเทนเนอร์ (ไม่มีหน่วยความจำพื้นฐาน) มันเป็นตัวชี้อัจฉริยะบางรูปแบบ ดังนั้นฉันคาดหวังว่าภาษาจะช่วยให้ฉันสามารถเปรียบเทียบตัววนซ้ำดังกล่าวเชื่อใจฉันว่า มุมมองกำลังชี้ไปยังชุดย่อยอื่น (หรือเหมือนกัน) ของคอนเทนเนอร์เดียวกัน

ดังนั้นคำถามของฉันคือฉันจะทำให้สิ่งนี้ใช้ได้กับ string_view เท่านั้นได้อย่างไร

(หมายถึงโดยไม่จำเป็นต้องสร้างคลาสช่วงที่กำหนดเองซึ่งจะมีตัววนซ้ำสองตัวเนื่องจากจะทำให้วัตถุประสงค์ของการใช้ std::string_view หมดไปตั้งแต่แรก)


person Domen Vrankar    schedule 23.09.2018    source แหล่งที่มา
comment
กรณีการใช้งานของคุณคืออะไร? ฉันไม่เห็นเหตุผลที่จะทำสิ่งที่คุณต้องการทำกับ string_views?   -  person NoSenseEtAl    schedule 23.09.2018
comment
@NoSenseEtAl ฉันกำลังแก้ไข boost::beast เพื่อใช้กับ std::string_view แทน boost::string_view โดยมีการเปลี่ยนแปลงน้อยที่สุด (ดู basic_parsed_list const_iterator class: github.com/boostorg/beast/blob/develop/include/boost/beast/http/ ก>) บน Linux ทำได้ทั้งหมด: github.com/boostorg/beast/pull/1241 และบน Windows มันใช้งานได้มากกว่านี้อีกเล็กน้อย...   -  person Domen Vrankar    schedule 24.09.2018
comment
@Justin นั่นคือ it == s.end() ส่วนที่เปลี่ยนเป็น it == &*s.end() ทำให้เกิดข้อผิดพลาดในการยืนยันรันไทม์ซึ่งไม่ควรยกเลิกการอ้างอิงตัววนซ้ำ (สำหรับส่วนที่เหลือของพอยน์เตอร์ระหว่าง start และ end-1 ที่จะใช้งานได้)   -  person Domen Vrankar    schedule 24.09.2018


คำตอบ (1)


ดูเหมือนว่าคุณต้องการทำงานกับพอยน์เตอร์แบบดิบ

หากคุณต้องการทำงานกับพอยน์เตอร์ดิบ ให้ใช้ .data() แทน .begin() และ .data()+.size() แทน end()

พอยน์เตอร์เหล่านี้ทำงานเหมือนกับที่คุณต้องการให้ตัววนซ้ำของมุมมองสตริงทำงาน

หากคุณต้องการตัววนซ้ำกลับ ptr-.data()+.begin() จะสร้างตัววนซ้ำอีกครั้ง (และ it-begin()+.data() เดินทางไปกลับที่ ptr)

person Yakk - Adam Nevraumont    schedule 24.09.2018