2008-10-11 38 views
70

Tôi đã đọc một số địa điểm khác biệt giữa c_str()data() (trong STL và các triển khai khác) là c_str() luôn bị hủy trong khi data() thì không. Theo như tôi đã thấy trong triển khai thực tế, họ thực hiện tương tự hoặc data() cuộc gọi c_str().chuỗi c_str() so với dữ liệu()

Tôi thiếu gì ở đây? Cách nào chính xác hơn để sử dụng trong trường hợp nào?

Trả lời

80

Các tài liệu là chính xác. Sử dụng c_str() nếu bạn muốn một chuỗi chấm dứt null.

Nếu người thực hiện muốn thực hiện data() về mặt số c_str() bạn không phải lo lắng, vẫn sử dụng data() nếu bạn không cần chuỗi bị vô hiệu, trong một số triển khai, nó có thể hoạt động tốt hơn c_str().

chuỗi không nhất thiết phải bao gồm dữ liệu nhân vật, họ có thể được sáng tác với các yếu tố của bất kỳ loại. Trong những trường hợp đó, data() có ý nghĩa hơn. c_str() theo ý kiến ​​của tôi chỉ thực sự hữu ích khi các phần tử của chuỗi của bạn dựa trên ký tự.

Thêm: Trong C++ 11 trở đi, cả hai hàm đều bắt buộc phải giống nhau. tức là data hiện được yêu cầu phải bị vô hiệu hóa. Theo cppreference: "Mảng được trả về là null bị chấm dứt, nghĩa là dữ liệu() và c_str() thực hiện cùng chức năng."

16

Ngay cả biết bạn đã thấy rằng họ làm như vậy, hoặc là .data() gọi .c_str(), nó không phải là chính xác khi cho rằng đây sẽ là trường hợp cho trình biên dịch khác. Cũng có thể trình biên dịch của bạn sẽ thay đổi với bản phát hành trong tương lai.

2 lý do để sử dụng std :: string:

std :: string có thể được sử dụng cho cả văn bản và dữ liệu nhị phân tùy ý.

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

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

Bạn nên sử dụng phương pháp .c_str() khi bạn đang sử dụng chuỗi của bạn như ví dụ 1.

Bạn nên sử dụng phương pháp .data() khi bạn đang sử dụng chuỗi của bạn làm ví dụ 2. Không bởi vì nó rất nguy hiểm khi sử dụng .c_str() trong những trường hợp này, nhưng vì rõ ràng hơn là bạn đang làm việc với dữ liệu nhị phân để những người khác xem xét mã của bạn.

cạm bẫy có thể xảy ra với việc sử dụng .data()

Các mã sau đây là sai và có thể gây ra một segfault trong chương trình của bạn:

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

Tại sao nó phổ biến đối với người thực hiện để làm cho .data() và .c_str() làm điều tương tự?

Bởi vì nó là hiệu quả hơn để làm như vậy. Cách duy nhất để làm cho .data() trả về một cái gì đó mà không phải là null chấm dứt, sẽ là có .c_str() hoặc .data() sao chép bộ đệm bên trong của chúng, hoặc chỉ sử dụng 2 bộ đệm. Có một bộ đệm null kết thúc duy nhất luôn luôn có nghĩa là bạn luôn có thể sử dụng chỉ một bộ đệm nội bộ khi thực hiện std :: string.

+6

Thực ra, điểm của .data() là không được sao chép bộ đệm trong. Điều này có nghĩa là việc thực hiện không phải lãng phí một char trên \ 0 cho đến khi cần thiết. Bạn sẽ không bao giờ muốn hai bộ đệm: nếu bạn gọi hàm .c_str(), hãy thêm \ 0 vào bộ đệm. .data() vẫn có thể trả về bộ đệm đó. – MSalters

+1

Đồng ý hoàn toàn nó sẽ là vô lý để sử dụng 2 bộ đệm. Làm thế nào để bạn biết đó là lý do tại sao .data được dự định? –

+0

@ BrianR.Bondy Tôi đã thử mã này: ..auto str = string {"Test \ 0String!" }; cout << "DỮ LIỆU:" << str.data() << endl; Đầu ra là "Kiểm tra" chứ không phải toàn bộ chuỗi, Tôi đã làm gì sai? – programmer

1

Trích từ ANSI ISO IEC 14882 2003 (C++ 03 tiêu chuẩn):

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

Nó đã được trả lời đã có, một số ghi chú về mục đích: Tự do thực hiện.

std::string hoạt động - ví dụ: lặp lại, ghép nối và đột biến phần tử - không cần trình kết thúc bằng 0. Trừ khi bạn vượt qua các string đến một chức năng mong đợi một chuỗi không chấm dứt, nó có thể được bỏ qua.

Điều này sẽ cho phép triển khai có dữ liệu chuỗi thực tế: string::substr có thể giữ tham chiếu đến dữ liệu chuỗi chia sẻ và phạm vi bắt đầu/kết thúc, tránh sao chép (và phân bổ bổ sung) của dữ liệu chuỗi thực tế. Việc triển khai sẽ trì hoãn bản sao cho đến khi bạn gọi c_str hoặc sửa đổi bất kỳ chuỗi nào. Không có bản sao nào được thực hiện nếu các strign liên quan chỉ đọc.

(việc thực hiện sao chép không thực sự thú vị trong môi trường đa luồng, cộng với tiết kiệm bộ nhớ/phân bổ điển hình không đáng giá mã phức tạp hơn ngày hôm nay, vì vậy hiếm khi được thực hiện).


Tương tự, string::data cho phép một đại diện nội bộ khác, ví dụ: một sợi dây (danh sách liên kết các đoạn dây). Điều này có thể cải thiện đáng kể các hoạt động chèn/thay thế. một lần nữa, danh sách các phân đoạn sẽ phải được thu gọn thành một phân đoạn khi bạn gọi c_str hoặc data.

20

Trong C++11/C++0x, data()c_str() không còn khác nhau. Và do đó, data() cũng được yêu cầu có kết thúc null vào cuối.

21.4.7.1 basic_string accessors [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 Returns: Một con trỏ p mà p + i == &operator[](i) cho mỗi i trong [0,size()].


21.4.5 basic_string yếu tố truy cập [string.access]

const_reference operator[](size_type pos) const noexcept;

1 Yêu cầu: pos < = size(). 2 Trả về: *(begin() + pos) if pos < size(), nếu không, tham chiếu đến đối tượng thuộc loại T có giá trị charT(); giá trị được tham chiếu sẽ không được sửa đổi.

+0

Điều gì xảy ra nếu chuỗi bao gồm dữ liệu không phải ký tự, hợp pháp cho dữ liệu chuỗi AFAIK, bao gồm cả null? – taz

+3

@taz Ngay cả khi lưu trữ dữ liệu nhị phân, C++ 11 yêu cầu 'std :: string' phân bổ thêm' char' cho dấu ''\ 0''. Khi bạn làm 'std :: string s (" \ 0 ");', cả hai 's.data() [0]' và 's.data() [1]' được bảo đảm để đánh giá là 0. – bcrist

Các vấn đề liên quan