เหตุใดจึงมีคลาสสตริงจำนวนมากในหน้าของ std :: string?


56

สำหรับฉันแล้วดูเหมือนว่าไลบรารี C ++ ที่ใหญ่กว่านั้นจะสร้างประเภทสตริงของตัวเองขึ้นมา ในรหัสลูกค้าที่คุณอาจจะต้องใช้อย่างใดอย่างหนึ่งจากห้องสมุด ( QString, CString, fbstringฯลฯ ฉันแน่ใจว่าทุกคนสามารถชื่อไม่กี่) หรือเก็บแปลงระหว่างชนิดมาตรฐานและเป็นหนึ่งในการใช้ห้องสมุด (ซึ่งใช้เวลาส่วนใหญ่เกี่ยวข้องกับการ อย่างน้อยหนึ่งสำเนา)

ดังนั้นมีความผิดพลาดบางอย่างหรือมีสิ่งผิดปกติstd::string(เช่นauto_ptrความหมายไม่ดี) หรือไม่? มีการเปลี่ยนแปลงใน C ++ 11 หรือไม่?


32
มันเรียกว่า "โรคที่ไม่ได้คิดค้นที่นี่"
Cat Plus Plus

10
@CatPlusPlus QString และ CString std ทั้งที่คาดการณ์ไว้ :: สตริง
Gort the Robot

8
@Cat Plus Plus: กลุ่มอาการนี้ดูเหมือนจะไม่ส่งผลกระทบต่อคลาส Java String
Giorgio

20
@Giorgio: โปรแกรมเมอร์ Java ไม่ว่างเกินไปในการประดิษฐ์วิธีแก้ปัญหาสำหรับข้อบกพร่องด้านภาษาที่ต้องกังวลเกี่ยวกับคลาสของสตริง (Android สร้างอัตลักษณ์สตริงโดยวิธี)
Cat Plus Plus

9
@Giorgio: นั่นอาจเป็นเพราะ Java ของ syntactic ที่สนับสนุนการเข้ารหัสjava.lang.String(ขาดตัวดำเนินการมากเกินไป ฯลฯ ) จะทำให้มันเจ็บปวดที่จะใช้สิ่งอื่น
หอยทากวิศวกรรม

คำตอบ:


57

ไลบรารี C ++ ที่ใหญ่กว่านั้นส่วนใหญ่เริ่มต้นก่อนหน้าstd::stringนี้ซึ่งเป็นมาตรฐาน คุณสมบัติอื่น ๆ ได้แก่ คุณสมบัติเพิ่มเติมที่ได้มาตรฐานช้าหรือยังไม่ได้มาตรฐานเช่นการสนับสนุน UTF-8 และการแปลงระหว่างการเข้ารหัส

หากห้องสมุดเหล่านี้ถูกนำไปใช้ในวันนี้พวกเขาอาจเลือกที่จะเขียนฟังก์ชั่นและตัววนซ้ำที่ทำงานกับstd::stringอินสแตนซ์


5
รองรับ UTF-8 เป็นมาตรฐานตั้งแต่ C ++ 98 ด้วยวิธีการที่กำหนดไว้ไม่สะดวกและมีการใช้งานบางส่วนซึ่งดูเหมือนว่าไม่มีใครสามารถใช้งานได้
AProgrammer

9
@AProgrammer: charรับประกันว่าจะมีขนาดใหญ่พอที่จะรองรับ codepoint UTF-8 ใด ๆ AFAIK นั่นเป็น "การสนับสนุน" อย่างเดียวที่ C ++ 98 มีให้
Ben Voigt

4
@ AProgrammer: การสนับสนุนนั้นไร้ประโยชน์จริงๆ
DeadMG

4
@ AProgrammer สถานที่นั้นเสียเนื่องจากเนื้อหาwchar_tมีขนาดไม่ใหญ่พอที่จะแสดงจุดรหัส Unicode ทั้งหมด นอกจากนี้ยังมีการสนทนาทั้งหมดเกี่ยวกับUTF-16 ซึ่งถือว่าเป็นอันตรายที่มีการโต้แย้งที่น่าสนใจอย่างมากที่ทำให้ UTF-8 ควรใช้เฉพาะ ...
Konrad Rudolph

6
@KonradRudolph ไม่ใช่ระบบสถานที่ซึ่งแตกหัก (คำจำกัดความของ wchar_t คือ "กว้างพอสำหรับชุดอักขระที่รองรับ"); ระบบที่มีความมุ่งมั่นที่จะ 16 บิต wchar_t ทำในเวลาเดียวกันมุ่งมั่นที่จะไม่สนับสนุน Unicode ผู้ร้ายคือ Unicode ซึ่งรับประกันได้ว่าจะไม่เคยใช้ codepoints ที่ต้องการมากกว่า 16 บิตจากนั้นระบบที่ส่งไปยัง 16 บิต wchar_t แล้วเปลี่ยนเป็น unicode เพื่อต้องการมากกว่า 16 บิต
AProgrammer

39

สตริงคือความลำบากใจใหญ่ของ C ++

สำหรับ 15 ปีแรกคุณไม่มีคลาสสตริงเลยบังคับให้คอมไพเลอร์ทุกตัวในทุกแพลตฟอร์มและผู้ใช้ทุกคนสร้างเอง

จากนั้นคุณทำสิ่งที่สับสนว่าควรจะเป็น API การจัดการสตริงแบบเต็มหรือเพียงแค่คอนเทนเนอร์ STL ด้วยอัลกอริทึมบางอย่างที่ทำซ้ำสิ่งที่อยู่ใน std :: Vector หรือแตกต่างกัน

ในกรณีที่การทำงานของสตริงที่ชัดเจนเช่นแทนที่ () หรือ mid () นั้นเกี่ยวข้องกับการวนซ้ำของตัววนซ้ำที่คุณต้องแนะนำคำหลัก 'อัตโนมัติ' ใหม่เพื่อให้การปรับคำสั่งในหน้าเดียวและทำให้คนส่วนใหญ่ยอมแพ้ทั้งภาษา .

และจากนั้นคุณมี unicode 'สนับสนุน' และ std :: wstring ที่ arghh .....

<พูดจาโผงผาง> ขอบคุณ - ตอนนี้ฉันรู้สึกดีขึ้นมาก


12
@DeadMG - ใช่และมันเป็นมาตรฐานในปี 1998 15 ปีหลังจากที่มันถูกคิดค้นและ 6 ปีหลังจากแม้แต่ MSFT ก็ใช้มัน ใช่ตัววนซ้ำเป็นวิธีที่มีประโยชน์ในการสร้างอาร์เรย์และรายการมีลักษณะเหมือนกันคุณคิดว่ามันเป็นวิธีที่ชัดเจนในการจัดการสตริงหรือไม่?
Martin Beckett

3
C กับคลาสถูกประดิษฐ์ขึ้นในปี 1983 ไม่ใช่ C ++ ไลบรารีมาตรฐานเดียวเท่านั้นที่ถูกกำหนดโดยมาตรฐาน - ซึ่งแปลกพอสามารถเกิดขึ้นได้เมื่อคุณมีมาตรฐานเท่านั้นดังนั้นวันที่ที่เร็วที่สุดที่เป็นไปได้สำหรับไลบรารีมาตรฐานใด ๆคือ 1998 และตัววนซ้ำอาจพิจารณาเท่ากับดัชนี แต่พิมพ์อย่างยิ่ง ฉันทั้งหมดสำหรับความจริงที่ว่า iterators ดูดเมื่อเทียบกับช่วง std::stringแต่ที่ไม่ได้จริงๆที่เฉพาะเจาะจงเพื่อ การขาดคลาส String ในปี 1983 ไม่ได้เป็นการพิสูจน์ว่ามีมากกว่านั้นในตอนนี้
DeadMG

8
ฉันคิดว่า iostreams เป็นความลำบากใจครั้งใหญ่ของ C ++ ...
Doug T.

18
@DeadMG ผู้คนกำลังใช้สิ่งที่เรียกว่า "C ++" เป็นเวลาหลายปีก่อนปี 1998 ฉันเขียนโปรแกรมแรกของฉันโดยใช้บางสิ่งที่เรียกว่า "C ++" ในปี 1985 ถ้าคุณต้องการบอกว่านี่ไม่ใช่ "ของจริง" C ++ แต่ก็ดี ก่อนหน้านี้เรากำลังเขียนโค้ดและต้องได้รับคลาสสตริงจากที่อื่น เมื่อเรามีฐานรหัสดั้งเดิมเหล่านี้เราไม่สามารถทิ้งพวกเขาหรือเขียนใหม่ตั้งแต่ต้นเมื่อเราได้มาตรฐาน ตอนนี้สิ่งที่ควรจะเกิดขึ้นคือควรมีคลาสสตริงที่มาพร้อมกับ cfront
Gort the Robot

8
@DeadMG - หากไม่มีใครใช้ภาษาจนกว่าจะได้รับใบรับรอง ISO จะไม่มีการใช้ภาษาใด ๆ เนื่องจากจะไม่ได้รับมาตรฐาน ISO ไม่มีมาตรฐาน ISO สำหรับแอสเซมเบลอร์ x86 แต่ฉันยินดีที่จะใช้แพลตฟอร์ม
Martin Beckett

32

ที่จริงแล้ว ... มีปัญหาหลายอย่างstd::stringและใช่แล้วมันจะดีขึ้นเล็กน้อยใน C ++ 11 แต่ขออย่าก้าวไปข้างหน้าตัวเอง

QStringและCStringเป็นส่วนหนึ่งของไลบรารีเก่าดังนั้นจึงมีอยู่ก่อน C ++ ที่เป็นมาตรฐาน (เหมือนกับ SGI STL) พวกเขาจึงต้องสร้างชั้นเรียน

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

ความกังวลอื่น ๆ ที่ไม่ได้ปรากฏที่นี่ (en vrac):

  • ใน C ++ 03 ไม่จำเป็นที่หน่วยเก็บข้อมูลจะต่อเนื่องกันทำให้การทำงานร่วมกันกับ C อาจยาก C ++ 11 แก้ไขสิ่งนี้
  • std::string กำลังเข้ารหัสโดยไม่รู้ตัวและไม่มีรหัสพิเศษสำหรับ UTF-8 มันง่ายที่จะเก็บสตริง UTF-8 ไว้ในนั้นและทำให้มันเสียหายโดยไม่ตั้งใจ
  • std::stringอินเทอร์เฟซถูกป่องหลายวิธีอาจถูกนำมาใช้เป็นฟังก์ชั่นฟรีและจำนวนมากถูกทำซ้ำเพื่อให้สอดคล้องกับทั้งอินเทอร์เฟซที่ใช้ดัชนีและอินเทอร์เฟซที่ใช้ตัววนซ้ำ

5
เรื่องความกังวล # 1 - C ++ 03 21.3.6 / 1 รับประกันว่าc_str()จะส่งคืนตัวชี้ไปยังที่เก็บข้อมูลที่ต่อเนื่องซึ่งให้การทำงานร่วมกันของ C บางอย่าง อย่างไรก็ตามคุณไม่สามารถแก้ไขข้อมูลที่ชี้ไปยัง vector<char>วิธีการแก้ปัญหาทั่วไปรวมถึงการใช้
John Dibling

@JohnDibling: ใช่และมีข้อ จำกัด อื่น: มันอาจจะเกิดขึ้นสำเนาในการจัดเก็บที่จัดสรรใหม่ (มาตรฐานไม่ได้บอกว่ามันจะไม่) แน่นอน C ++ 11 ไม่ได้ป้องกันการคัดลอกทั้ง แต่เนื่องจากคุณสามารถก็ไม่&s[0]มันไม่สำคัญอีกต่อไป :)
Matthieu เมตร

1
@MatthieuM: ตัวชี้ที่ได้รับผ่าน&s[0]อาจไม่ได้ชี้ไปที่สตริงที่สิ้นสุดด้วย NUL (ยกเว้นว่าc_str()ถูกเรียกตั้งแต่การแก้ไขครั้งล่าสุด)
Ben Voigt

2
@Matthieu: ไม่อนุญาตให้ใช้บัฟเฟอร์อื่น " c_str()การส่งคืน: ตัวชี้pดังกล่าวว่าp + i == &operator[](i)สำหรับแต่ละiใน[0,size()]"
Ben Voigt

3
สิ่งที่ควรค่าแก่การสังเกตก็คือไม่มีใครในใจที่ถูกต้องใช้ MFC อีกต่อไปดังนั้นจึงเป็นการยากที่จะโต้แย้งว่า CString เป็นคลาสสตริงใน C ++ ที่ทันสมัย
DeadMG

7

นอกเหนือจากเหตุผลที่โพสต์ที่นี่ยังมีอีกคนหนึ่ง - compability ไบนารี ตัวเขียนของ Library ไม่สามารถควบคุมstd::stringการใช้งานที่คุณกำลังใช้อยู่และมีรูปแบบหน่วยความจำแบบเดียวกันกับที่ใช้หรือไม่

std::stringเป็นเทมเพลตดังนั้นการนำไปปฏิบัติจะถูกนำมาจากส่วนหัว STL ในพื้นที่ของคุณ ตอนนี้จินตนาการว่าคุณกำลังใช้รุ่น STL ที่ปรับให้เหมาะสมกับประสิทธิภาพภายในเครื่องซึ่งเข้ากันได้กับมาตรฐานอย่างสมบูรณ์ ตัวอย่างเช่นคุณอาจเลือกที่จะบุกรุกบัฟเฟอร์คงที่ในแต่ละครั้งstd::stringเพื่อลดจำนวนการจัดสรรแบบไดนามิกและแคชที่หายไป ดังนั้นรูปแบบหน่วยความจำและ / หรือขนาดของการใช้งานของคุณจึงแตกต่างจากของไลบรารี

ถ้าเลย์เอาต์นั้นแตกต่างกันไปบางstd::stringฟังก์ชั่นสมาชิกจะเรียกใช้อินสแตนซ์ที่ส่งจากไลบรารีไปยังไคลเอนต์หรือวิธีอื่นอาจล้มเหลวโดยขึ้นอยู่กับสมาชิกที่ถูกเลื่อน

หากขนาดแตกต่างกันเช่นกันประเภทห้องสมุดทั้งหมดที่มีstd::stringสมาชิกจะปรากฏเป็นขนาดแตกต่างกันเมื่อทำการตรวจสอบในไลบรารีและในรหัสลูกค้า สมาชิกข้อมูลที่ติดตามstd::stringสมาชิกจะมีออฟเซ็ตที่เลื่อนออกไปเช่นกันและการเข้าถึงโดยตรง / อินไลน์ accessor ที่เรียกจากไคลเอนต์จะส่งคืนขยะแม้ว่า "มองตกลง" เมื่อทำการดีบักไลบรารีเอง

Bottomline - ถ้าไลบรารี่และรหัสลูกค้านั้นคอมไพล์ agains std::stringเวอร์ชันต่างๆ พวกมันจะลิงค์ได้ดี แต่มันอาจส่งผลให้เกิดข้อผิดพลาดที่น่ารังเกียจและเข้าใจยาก หากคุณเปลี่ยนstd::stringการใช้งานไลบรารีทั้งหมดที่เปิดเผยสมาชิกจาก STL จะต้องทำการคอมไพล์ใหม่เพื่อให้ตรงกับstd::stringเลย์เอาต์ของลูกค้า และเนื่องจากโปรแกรมเมอร์ต้องการห้องสมุดของพวกเขาจะแข็งแกร่งคุณจะไม่ค่อยเห็นstd::stringสัมผัสได้ทุกที่

เพื่อความเป็นธรรมสิ่งนี้ใช้กับ STL ทุกประเภท IIRC ไม่มีเลย์เอาต์ของหน่วยความจำที่มีมาตรฐาน


2
คุณต้องเป็นโปรแกรมเมอร์ * nix ความเข้ากันได้ของไบนารี C ++ นั้นไม่เท่ากันในทุกแพลตฟอร์มและโดยเฉพาะในคลาส Windows NO ที่มีข้อมูลสมาชิกจะสามารถเคลื่อนย้ายได้ระหว่างคอมไพเลอร์
Ben Voigt

(ผมหมายถึงยกเว้นประเภท POD และความต้องการบรรจุแม้อย่างชัดเจนแล้วมีความจำเป็น)
เบนยต์

1
ขอบคุณสำหรับอินพุตแม้ว่าฉันจะไม่ได้พูดถึงคอมไพเลอร์ที่แตกต่างกัน แต่ฉันกำลังพูดถึง STL ที่แตกต่างกัน
gwiazdorrr

1
+1: ABI เป็นเหตุผลอย่างมากที่จะนำเวอร์ชั่นคอมไพเลอร์ของคุณมาให้คุณ สำหรับสิ่งนั้นฉันหวังว่านี่จะเป็นคำตอบที่ได้รับการยอมรับ
Thomas Eding

6

มีคำตอบมากมายสำหรับคำถาม แต่นี่คือบางส่วน:

  1. มรดก ไลบรารีสตริงและคลาสจำนวนมากถูกเขียนก่อนหน้าเพื่อการมีอยู่ของ std :: string

  2. สำหรับความเข้ากันได้กับรหัสใน C. ไลบรารี std :: string คือ C ++ ซึ่งมีไลบรารีสตริงอื่นที่ทำงานกับ C และ C ++

  3. เพื่อหลีกเลี่ยงการจัดสรรแบบไดนามิก library std :: string ใช้การจัดสรรแบบไดนามิกและอาจไม่เหมาะสำหรับระบบฝังตัว, การขัดจังหวะหรือรหัสที่เกี่ยวข้องแบบเรียลไทม์หรือสำหรับการทำงานระดับต่ำ

  4. แม่แบบ ไลบรารี std :: string ขึ้นอยู่กับเท็มเพลต จนกระทั่งเมื่อไม่นานมานี้มีคอมไพเลอร์ C ++ จำนวนหนึ่งที่ทำงานได้ไม่ดีหรือแม้แต่การสนับสนุนเทมเพลตแบบบั๊กกี้ น่าเสียดายที่ฉันทำงานในอุตสาหกรรมที่ใช้เครื่องมือที่กำหนดเองจำนวนมากและหนึ่งในเครื่องมือของเราจากผู้เล่นรายใหญ่ในอุตสาหกรรมไม่สนับสนุน "100%" อย่างเป็นทางการ "C ++ (พร้อมด้วย buggy stuff เป็นเทมเพลตและคณะ)

อาจมีเหตุผลที่ถูกต้องอีกมากมายเช่นกัน


2
"เป็นธรรมเมื่อเร็ว ๆ นี้" ความหมาย "เป็นเวลาสิบปีแล้วที่ Visual Studio มีเหตุผลสนับสนุนพวกเขา"
DeadMG

@DeadMG - Visual Studio ไม่ได้เป็นเพียงคอมไพเลอร์ที่ไม่ได้มาตรฐานในโลก ฉันทำงานในวิดีโอเกมและเรามักจะทำงานกับคอมไพเลอร์ที่กำหนดเองสำหรับแพลตฟอร์มฮาร์ดแวร์ที่ไม่ได้เผยแพร่ (เกิดขึ้นทุก ๆ สองสามปีในรอบคอนโซลหรือเมื่อฮาร์ดแวร์ใหม่ปรากฏขึ้น) "พอใช้เร็ว ๆ นี้" หมายถึงวันนี้ - ตอนนี้คอมไพเลอร์บางตัวไม่รองรับเทมเพลต ฉันไม่สามารถระบุได้โดยไม่ละเมิด NDA แต่ขณะนี้ฉันกำลังทำงานบนแพลตฟอร์มที่มีชุดเครื่องมือที่กำหนดเองซึ่ง C + + สนับสนุน - โดยเฉพาะอย่างยิ่งการปฏิบัติตามแม่แบบ - ถือว่าเป็น "ทดลอง"
Adisak

4

ส่วนใหญ่เกี่ยวกับ Unicode การสนับสนุนมาตรฐานสำหรับ Unicode นั้นดีที่สุดและทุกคนก็มีความต้องการ Unicode ของตัวเอง ยกตัวอย่างเช่น ICU รองรับทุกฟังก์ชั่นของ Unicode ที่คุณอาจต้องการหลังอินเตอร์เฟซที่สร้างขึ้นโดยอัตโนมัติจาก Java ที่น่าขยะแขยงที่สุดที่คุณสามารถจินตนาการได้และถ้าคุณใช้ Unix ที่ติดอยู่กับ UTF-16 อาจไม่ใช่ความคิดของคุณ ช่วงเวลาที่ดี.

นอกจากนี้หลายคนต้องการระดับการสนับสนุน Unicode ที่แตกต่างกันไม่ใช่ทุกคนต้องการ API เลย์เอาต์ข้อความที่ซับซ้อนและสิ่งต่าง ๆ ดังนั้นจึงเป็นเรื่องง่ายที่จะเห็นว่าทำไมมีคลาสสตริงจำนวนมาก - Standard one ค่อนข้างน่าสนใจและทุกคนมีความต้องการที่แตกต่างจากคลาสใหม่โดยไม่มีใครจัดการเพื่อสร้างคลาสเดียวที่สามารถรองรับ Unicode ได้หลายแพลตฟอร์มพร้อมอินเทอร์เฟซที่น่าพอใจ

ในความคิดของฉันนี่เป็นความผิดของคณะกรรมการ C ++ ที่ให้การสนับสนุน Unicode ในปี 1998 หรือ 2003 ไม่ถูกต้องซึ่งอาจเข้าใจได้ แต่ไม่ใช่ใน C ++ 11 หวังว่าใน C ++ 17 พวกเขาจะทำได้ดีกว่า


สวัสดี C ++ 20 ที่นี่เดาว่าเกิดอะไรขึ้นกับการสนับสนุน Unicode
สัญจรภายใน

-4

เป็นเพราะโปรแกรมเมอร์ทุกคนมีบางสิ่งที่จะพิสูจน์และรู้สึกว่าจำเป็นที่จะต้องสร้างคลาสที่ยอดเยี่ยมและรวดเร็วยิ่งขึ้นสำหรับฟังก์ชั่นที่ยอดเยี่ยมของพวกเขา โดยปกติแล้วจะมีความฟุ่มเฟือยเล็กน้อยและนำไปสู่การแปลงสตริงพิเศษทุกประเภทในประสบการณ์ของฉัน


7
นี่เป็นความจริงฉันคาดหวังว่าจะเห็นการใช้งาน String จำนวนใกล้เคียงกันในภาษาเช่น Java ซึ่งมีการใช้งานที่ดีมาตลอด
Bill K

@BillK Java String เป็นที่สิ้นสุดดังนั้นคุณต้องใส่ฟังก์ชั่นใหม่ที่อื่น

และประเด็นของฉันคือแม้จะเป็นครั้งสุดท้ายในรอบ 20 ปีฉันไม่เคยเห็นใครเขียน impelementation สตริงที่กำหนดเอง (ดีฉันพยายามที่จะปรับปรุงประสิทธิภาพการเรียงสตริง แต่มันกลับกลายเป็น java เป็นฉลาดมากที่สตริง + สตริงกว่าคุณ ' ลองนึกดู)
Bill K

2
@ บิล: นั่นอาจจะเกี่ยวข้องกับวัฒนธรรมที่แตกต่าง C ++ ดึงดูดผู้ที่ต้องการเข้าใจรายละเอียดในระดับต่ำ Java ดึงดูดผู้ที่ต้องการทำงานให้เสร็จโดยใช้หน่วยการสร้างของคนอื่น (โปรดทราบว่านี่ไม่ใช่คำแถลงเกี่ยวกับบุคคลใดบุคคลหนึ่งที่เลือกใช้ภาษาใดภาษาหนึ่ง แต่เกี่ยวกับเป้าหมายและวัฒนธรรมการออกแบบของแต่ละภาษา)
Ben Voigt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.