2012-04-05 12 views
12

"Phải luôn sử dụng std::string qua chuỗi kiểu c (char *)" là lời khuyên xuất hiện cho hầu hết mọi mã nguồn được đăng tại đây. Trong khi lời khuyên là không có nghi ngờ tốt, các câu hỏi thực tế được giải quyết không cho phép để xây dựng trên lý do tại sao? khía cạnh của lời khuyên chi tiết. Câu hỏi này là để phục vụ như một trình giữ chỗ cho cùng một.Tại sao nên sử dụng std :: chuỗi trên chuỗi kiểu c trong C++?

Một câu trả lời tốt nên bao gồm các khía cạnh sau (chi tiết):

  1. Tại sao ta nên sử dụng std::string qua chuỗi c kiểu trong C++?
  2. Những bất lợi (nếu có) của thực tiễn được đề cập trong #1 là gì?
  3. Các trường hợp đối diện với lời khuyên được đề cập trong #1 là phương pháp hay?
+0

Tôi dự định gắn thẻ [C++ - Faq] này (http://stackoverflow.com/questions/tagged/c%2b%2b-faq) và sẽ thảo luận tương tự trong [C++ Lounge] (http: // chat .stackoverflow.com/phòng/10/loungec) ngay. –

+2

Điều này vẫn đang được hỏi vào năm 2012 ?! Ngoài ra, khi nào là lời khuyên để sử dụng 'std :: string' bao giờ ** không ** kèm theo hợp lý hóa? –

+1

@KarlKnechtel: Xin lỗi, Có vẻ tôi là một người mới sử dụng C++ không giống bạn :) Tuy nhiên, tôi sẽ bận tâm đọc toàn bộ câu hỏi và hiểu mục đích đằng sau nó thay vì chỉ đọc tiêu đề trước khi bình luận. –

Trả lời

13
  1. std :: chuỗi quản lý bộ nhớ của riêng mình, vì vậy bạn có thể sao chép, tạo, tiêu diệt chúng dễ dàng.
  2. Bạn không thể sử dụng bộ đệm của riêng mình làm chuỗi std ::.
  3. Bạn cần chuyển chuỗi c/bộ đệm vào thứ gì đó dự kiến ​​sẽ sở hữu bộ đệm - chẳng hạn như thư viện C bên thứ ba.
4

Vâng, nếu bạn chỉ cần cần một mảng ký tự, tiêu chuẩn :: chuỗi cung cấp ít lợi thế. Nhưng đối mặt với nó, bao lâu thì trường hợp đó? Bằng cách gói một mảng char với chức năng bổ sung như std :: string does, bạn có được cả sức mạnh và hiệu quả cho một số hoạt động.

Ví dụ: xác định độ dài của một mảng ký tự yêu cầu "đếm" các ký tự trong mảng. Ngược lại, một chuỗi std :: cung cấp một hoạt động hiệu quả cho nhiệm vụ cụ thể này. (Xem https://stackoverflow.com/a/1467497/129622)

  1. Đối với sức mạnh, hiệu quả và sự tỉnh táo
  2. bộ nhớ lớn hơn dấu chân hơn "chỉ là" một mảng char
  3. Khi bạn chỉ cần một loạt các ký tự
2

3) Các lời khuyên luôn luôn sử dụng string tất nhiên phải được thực hiện với một nhúm cảm giác thông thường. Chuỗi ký tự là const char[] và nếu bạn chuyển một chữ vào hàm có số const char* (ví dụ: std::ifstream::open()) thì hoàn toàn không có điểm nào được gói trong số std::string.

-1

Nói chung, bạn nên luôn sử dụng std :: string vì nó ít bị lỗi hơn. Hãy nhận biết, rằng chi phí bộ nhớ của std :: string là đáng kể. Gần đây tôi đã thực hiện một số thí nghiệm về std :: string overhead. Nói chung nó là khoảng 48 byte! Bài viết có tại đây: http://jovislab.com/blog/?p=76.

+1

Một điều đáng tiếc là tối ưu hóa chuỗi nhỏ là một điều tuyệt vời. – Puppy

+0

Tất cả phụ thuộc vào việc triển khai. Nhưng trong thực tế, không có công cụ gỡ lỗi, việc nghe lỏm không đáng kể. –

+0

* Đó là * đáng kể. Với -O2 và không có bất kỳ -g, G ++ vẫn mất 24 byte cho một chuỗi on-byte. Tôi giả sử như vậy là cho Visual Studio. – asanoki

1

Một char * về cơ bản là một con trỏ trỏ đến một ký tự. Những gì C làm thường xuyên làm cho con trỏ trỏ đến ký tự đầu tiên trong một mảng.

Chuỗi std :: là một lớp giống như vectơ.Bên trong, nó xử lý việc lưu trữ một mảng các ký tự và cung cấp cho người dùng một số hàm thành viên để thao tác mảng được lưu trữ cũng như một số toán tử bị quá tải.

lý do để sử dụng một char * trên một std :: string:

C backwards-compatibility. 
Performance (potentially). 
char*s have lower-level access. 

lý do để sử dụng một std :: string hơn một char *:

Much more intuitive to use. 
Better searching, replacement, and manipulation functions. 
Reduced risk of segmentation faults. 

Ví dụ:

char * phải được sử dụng trong conjuction với một mảng char, hoặc với một mảng char được phân bổ động. Sau khi tất cả, một con trỏ là vô giá trị, trừ khi nó thực sự trỏ đến một cái gì đó. Điều này chủ yếu được sử dụng trong các chương trình C:

char somebuffer[100] = "a string"; 
char* ptr = somebuffer; // ptr now points to somebuffer 
cout << ptr; // prints "a string" 
somebuffer[0] = 'b'; // change somebuffer 
cout << ptr; // prints "b string" 

thông báo rằng khi bạn thay đổi 'người chơi', 'ptr' cũng thay đổi. Điều này là do somebuffer là chuỗi thực tế trong trường hợp này. ptr chỉ điểm/đề cập đến nó.

Với std :: string nó ít kỳ lạ:

std::string a = "a string"; 
std::string b = a; 
cout << b; // prints "a string" 
a[0] = 'b'; // change 'a' 
cout << b; // prints "a string" (not "b string") 

Ở đây, bạn có thể thấy rằng việc thay đổi 'a' không ảnh hưởng 'b', vì 'b' là chuỗi thực tế. Tuy nhiên, thực sự, sự khác biệt chính là với mảng char, bạn chịu trách nhiệm quản lý bộ nhớ, trong khi std :: string thực hiện điều đó cho bạn. Trong C++, có rất ít lý do để sử dụng mảng char trên chuỗi. 99 lần trong số 100 bạn tốt hơn với một chuỗi.

Cho đến khi bạn hoàn toàn hiểu được quản lý bộ nhớ và con trỏ, chỉ cần tiết kiệm cho mình một số nhức đầu và sử dụng std :: string.

+0

Tôi nghi ngờ tuyên bố về hiệu suất tốt hơn của các chuỗi C. Nó * * có ít chi phí bộ nhớ hơn, điều này có thể rất quan trọng nếu bạn có nhiều chuỗi nhỏ (ví dụ: trong phân tích cú pháp hoặc tin sinh học, trong đó 'std :: string' có thể bị cấm). –

+0

Sử dụng char * cho phép bạn kiểm soát nhiều hơn những gì đang diễn ra "đằng sau" cảnh, có nghĩa là bạn có thể điều chỉnh hiệu suất nếu cần. –

1

Tại sao một người dùng std :: chuỗi trên chuỗi kiểu c trong C++?

Lý do chính là giải phóng bạn khỏi việc quản lý toàn bộ thời gian của dữ liệu chuỗi. Bạn chỉ có thể coi chuỗi là giá trị và để cho trình biên dịch/thư viện lo lắng về việc quản lý bộ nhớ.

Quản lý thủ công phân bổ bộ nhớ và thời gian tồn tại là tẻ nhạt và dễ bị lỗi.

Những bất lợi (nếu có) của thực tiễn được đề cập trong # 1 là gì?

Bạn từ bỏ quyền kiểm soát phân bổ và sao chép bộ nhớ. Điều đó có nghĩa là bạn kết thúc với một chiến lược quản lý bộ nhớ được chọn bởi nhà cung cấp toolchain của bạn chứ không phải là lựa chọn để phù hợp với nhu cầu của chương trình của bạn.

Nếu bạn không cẩn thận, bạn có thể kết thúc với rất nhiều sao chép dữ liệu không cần thiết (trong một thực hiện phi refcounted) hoặc thao tác tính tham khảo (trong một thực hiện refcounted)

Trong một dự án hỗn hợp bất kỳ ngôn ngữ function mà đối số của nó sử dụng std :: string hoặc bất kỳ cấu trúc dữ liệu nào có chứa std :: string sẽ không thể được sử dụng trực tiếp từ các ngôn ngữ khác.

Các trường hợp đối diện với lời khuyên được đề cập trong # 1 là một phương pháp hay?

Những người khác nhau sẽ có ý kiến ​​khác nhau về vấn đề này nhưng IMO

  • Đối với đối số chức năng đi qua chuỗi trong "const char *" là một lựa chọn tốt vì nó tránh unnessacery sao chép/refcouning và đưa ra sự linh hoạt gọi về những gì họ vượt qua.
  • Đối với những thứ được sử dụng trong tương tác với các ngôn ngữ khác, bạn có ít sự lựa chọn nhưng phải sử dụng các chuỗi kiểu c.
  • Khi bạn có giới hạn độ dài đã biết, có thể sử dụng mảng có kích thước cố định nhanh hơn.
  • Khi xử lý các chuỗi rất dài, có thể tốt hơn khi sử dụng một công trình chắc chắn sẽ được nạp lại thay vì sao chép (chẳng hạn như mảng ký tự được bao bọc trong shared_ptr) hoặc thực sự sử dụng một loại cấu trúc dữ liệu khác hoàn toàn