สตริง c_str () กับ data ()


103

ฉันได้อ่านสถานที่หลายแห่งที่ความแตกต่างระหว่างc_str()และdata()(ใน STL และการใช้งานอื่น ๆ ) นั้นc_str()จะถูกยกเลิกเสมอในขณะที่data()ไม่ใช่ เท่าที่ผมได้เห็นในการใช้งานที่เกิดขึ้นจริงที่พวกเขาจะทำเหมือนกันหรือโทรdata()c_str()

ฉันพลาดอะไรไปที่นี่? ข้อใดถูกต้องมากกว่าในการใช้ในสถานการณ์ใด

คำตอบ:


109

เอกสารถูกต้อง ใช้c_str()ถ้าคุณต้องการสตริงที่สิ้นสุดด้วยค่าว่าง

หากผู้ใช้มีความตั้งใจที่จะนำไปใช้data()ในแง่ที่c_str()คุณไม่ต้องกังวล แต่ยังคงใช้data()หากคุณไม่ต้องการให้สตริงถูกยกเลิกโดยว่างในการใช้งานบางอย่างอาจทำงานได้ดีกว่า c_str ()

สตริงไม่จำเป็นต้องประกอบด้วยข้อมูลอักขระสามารถประกอบด้วยองค์ประกอบประเภทใดก็ได้ ในกรณีเหล่านั้นdata()มีความหมายมากกว่า c_str()ในความคิดของฉันมีประโยชน์จริงๆก็ต่อเมื่อองค์ประกอบของสตริงของคุณเป็นแบบอักขระ

พิเศษ : ใน C ++ 11 เป็นต้นไปฟังก์ชันทั้งสองจะต้องเหมือนกัน กล่าวdataคือตอนนี้จำเป็นต้องสิ้นสุดด้วยโมฆะ อ้างอิงจากcppreference : "อาร์เรย์ที่ส่งคืนสิ้นสุดด้วยค่า null นั่นคือ data () และ c_str () ทำหน้าที่เดียวกัน"


4
พิเศษ 2: ใน C ++ 17 เป็นต้นไปขณะนี้ยังมีโอเวอร์โหลดแบบ non-const .data()ด้วยดังนั้นจึงไม่เทียบเท่ากับสตริงที่ไม่คงที่อีกต่อไป
Deduplicator

29

ในC ++ 11 / C ++ 0x , data()และc_str()จะไม่แตกต่างกัน ดังนั้นจึงdata()จำเป็นต้องมีการยกเลิกว่างในตอนท้ายเช่นกัน

21.4.7.1 basic_stringaccessors [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 การส่งคืน: ตัวชี้หน้าดังกล่าวว่าp + i == &operator[](i)สำหรับแต่ละในi[0,size()]


21.4.5 การเข้าถึงองค์ประกอบ basic_string [string.access]

const_reference operator[](size_type pos) const noexcept;

1 ต้องการ: pos <= size () 2 ผลตอบแทน: *(begin() + pos) if pos < size()มิฉะนั้นการอ้างอิงถึงออบเจ็กต์ประเภท T ที่มีค่าค่าcharT();ที่อ้างอิงจะต้องไม่เป็น modi fi ed


จะเกิดอะไรขึ้นถ้าสตริงประกอบด้วยข้อมูลที่ไม่ใช่อักขระซึ่งถูกกฎหมายสำหรับข้อมูลสตริง AFAIK รวมทั้ง null?
taz

3
@taz แม้ในขณะที่การจัดเก็บข้อมูลไบนารี, C ++ 11 กำหนดให้std::stringจัดสรรเป็นพิเศษสำหรับการต่อท้ายchar '\0'เมื่อคุณทำstd::string s("\0");ทั้งสองอย่างs.data()[0]และs.data()[1]รับประกันว่าจะประเมินเป็น 0
bcrist

20

แม้จะรู้ว่าคุณเคยเห็นว่าพวกเขาทำเช่นเดียวกันหรือที่. data () เรียก. c_str () มันไม่ถูกต้องที่จะคิดว่านี่จะเป็นกรณีสำหรับคอมไพเลอร์อื่น ๆ อาจเป็นไปได้ว่าคอมไพเลอร์ของคุณจะเปลี่ยนไปพร้อมกับรุ่นในอนาคต

2 เหตุผลในการใช้ std :: string:

std :: string สามารถใช้ได้กับทั้งข้อความและข้อมูลไบนารีโดยพลการ

//Example 1
//Plain text:
std::string s1;
s1 = "abc";

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

คุณควรใช้เมธอด. c_str () เมื่อคุณใช้สตริงของคุณดังตัวอย่างที่ 1

คุณควรใช้เมธอด. data () เมื่อคุณใช้สตริงของคุณเป็นตัวอย่าง 2 ไม่ใช่เพราะการใช้. c_str () ในกรณีเหล่านี้เป็นเรื่องที่น่ากลัว แต่เนื่องจากคุณกำลังทำงานกับข้อมูลไบนารีให้ผู้อื่นตรวจสอบอย่างชัดเจน รหัสของคุณ

ข้อผิดพลาดที่อาจเกิดขึ้นกับการใช้. data ()

รหัสต่อไปนี้ไม่ถูกต้องและอาจทำให้เกิดข้อผิดพลาดในโปรแกรมของคุณ:

std::string s;
s = "abc";   
char sz[512]; 
strcpy(sz, s.data());//This could crash depending on the implementation of .data()

เหตุใดจึงเป็นเรื่องปกติที่ผู้ใช้ที่ทำให้. data () และ. c_str () ทำสิ่งเดียวกัน

เนื่องจากมีประสิทธิภาพมากกว่าในการทำเช่นนั้น วิธีเดียวที่จะทำให้. data () ส่งคืนบางสิ่งที่ไม่ถูกยกเลิกด้วย null คือการมี. c_str () หรือ. data () คัดลอกบัฟเฟอร์ภายในของมันหรือใช้เพียง 2 บัฟเฟอร์ การมีบัฟเฟอร์ที่สิ้นสุดด้วย null เพียงครั้งเดียวหมายความว่าคุณสามารถใช้บัฟเฟอร์ภายในเพียงตัวเดียวเมื่อใช้ std :: string


6
จริงๆแล้วจุดของ. data () คือไม่ควรคัดลอกบัฟเฟอร์ภายใน ซึ่งหมายความว่าการใช้งานไม่จำเป็นต้องเสียถ่านใน \ 0 จนกว่าจะจำเป็น คุณไม่ต้องการบัฟเฟอร์สองตัว: ถ้าคุณเรียก. c_str () ให้ใส่ \ 0 ต่อท้ายบัฟเฟอร์ .data () ยังคงสามารถส่งคืนบัฟเฟอร์นั้นได้
MSalters

2
เห็นด้วยอย่างเต็มที่ว่าจะใช้บัฟเฟอร์ 2 ตัวแบบไร้สาระ คุณรู้ได้อย่างไรว่าทำไม. data จึงถูกสร้างขึ้นมา?
Brian R.Bondy

@ BrianR.Bondy ฉันลองใช้รหัสนี้: .. auto str = string {"Test \ 0String!" }; cout << "DATA:" << str.data () << endl; ผลลัพธ์คือ "Test" ไม่ใช่ทั้งสตริงฉันทำอะไรผิด
โปรแกรมเมอร์

ส่วนสุดท้ายไม่ถูกต้องข้อมูลและ c_str สามารถใช้บัฟเฟอร์เดียวกันได้โดยที่ไม่มีการสิ้นสุด 0 - c_str สามารถเพิ่ม 0 ในการโทรครั้งแรก
จำ Monica

โปรดทราบ c ++ 11 สร้าง. data () นามแฝงสำหรับ. c_str ()
hanshenrik

3

ได้รับคำตอบแล้วหมายเหตุบางประการเกี่ยวกับวัตถุประสงค์: เสรีภาพในการนำไปใช้งาน

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

สิ่งนี้จะช่วยให้การใช้งานมีสตริงย่อยแชร์ข้อมูลสตริงจริง: string::substrสามารถเก็บการอ้างอิงถึงข้อมูลสตริงที่แชร์ไว้ภายในและช่วงเริ่มต้น / สิ้นสุดโดยหลีกเลี่ยงการคัดลอก (และการจัดสรรเพิ่มเติม) ของข้อมูลสตริงจริง การนำไปใช้งานจะเลื่อนการคัดลอกออกไปจนกว่าคุณจะเรียกใช้ c_str หรือแก้ไขสตริงใด ๆ จะไม่มีการทำสำเนาหากมีการอ่านข้อความที่เกี่ยวข้อง

(การใช้งาน copy-on-write ไม่ค่อยสนุกนักในสภาพแวดล้อมแบบมัลติเธรดรวมทั้งการประหยัดหน่วยความจำ / การจัดสรรโดยทั่วไปไม่คุ้มกับโค้ดที่ซับซ้อนกว่าในปัจจุบันดังนั้นจึงไม่ค่อยได้ทำ)


ในทำนองเดียวกันstring::dataอนุญาตให้มีการแสดงภายในที่แตกต่างกันเช่นเชือก (รายการที่เชื่อมโยงของส่วนสตริง) สิ่งนี้สามารถปรับปรุงการดำเนินการแทรก / แทนที่ได้อย่างมาก อีกรายชื่อของกลุ่มจะต้องทรุดลงไปส่วนเดียวเมื่อคุณโทรหรือc_strdata


2

อ้างจากANSI ISO IEC 14882 2003(C ++ 03 Standard):

    21.3.6 basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
    Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.

    const charT* data() const;

    Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
    Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.

2

ค่าคอมมิชชั่นที่ผ่านมาทั้งหมดเป็นความสอดคล้องกัน แต่ฉันต้องการเพิ่มด้วยว่าเริ่มต้นใน c ++ 17 str.data () ส่งคืนถ่าน * แทน const char *


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