Thời gian tồn tại của std :: string :: c_str () là gì?


100

Trong một trong các chương trình của tôi, tôi phải giao diện với một số mã kế thừa hoạt động với const char*.

Giả sử tôi có một cấu trúc giống như sau:

struct Foo
{
  const char* server;
  const char* name;
};

Ứng dụng cấp cao hơn của tôi chỉ giải quyết vấn đề std::string, vì vậy tôi nghĩ đến việc sử dụng std::string::c_str()để lấy lại const char*con trỏ.

Nhưng thời gian tồn tại là c_str()gì?

Tôi có thể làm điều gì đó như thế này mà không phải đối mặt với hành vi không xác định không?

{
  std::string server = "my_server";
  std::string name = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

Hay tôi phải ngay lập tức sao chép kết quả của c_str()đến một nơi khác?

Cảm ơn bạn.


Đã xảy ra với tôi khi tôi xác định một chuỗi cục bộ trong một hàm và trả về .c_str(). Tôi không hiểu lý do tại sao đôi khi tôi chỉ nhận được một phần của chuỗi, cho đến khi tôi hiểu rằng const char*không sống mãi mãi, nhưng cho đến khi chuỗi bị phá hủy
SomethingSomething

Câu trả lời:


85

Các c_str()kết quả trở nên không hợp lệ nếu std::stringbị phá hủy hoặc nếu một hàm thành viên không const của chuỗi được gọi. Vì vậy, thông thường bạn sẽ muốn tạo một bản sao của nó nếu bạn cần giữ nó.

Trong trường hợp ví dụ của bạn, có vẻ như kết quả của c_str()được sử dụng một cách an toàn, vì các chuỗi không được sửa đổi trong phạm vi đó. (Tuy nhiên, chúng tôi không biết use_foo()hoặc ~Foo()có thể đang làm gì với những giá trị đó; nếu họ sao chép các chuỗi ở nơi khác, thì họ phải sao chép đúng chứ không chỉ sao chép các charcon trỏ.)


Con trỏ c_str () có thể không hợp lệ nếu đối tượng std :: string là một đối tượng tự động nằm ngoài phạm vi hoặc trong lệnh gọi hàm tạo luồng.
GuruM 16/10/12

Bạn có thể vui lòng giải thích non-const member function of the string is called.?
Mathew Kurian

2
"Hàm thành viên không phải const" là bất kỳ hàm thành viên nào không được đánh dấu bằng consttừ khóa. Một hàm như vậy có thể làm thay đổi nội dung của chuỗi, trong trường hợp đó, chuỗi có thể cần phân bổ lại bộ nhớ cho phiên bản kết thúc bằng null của chuỗi được trả về c_str(). Ví dụ: size()length()are const, vì vậy bạn có thể gọi chúng mà không cần lo lắng về chuỗi thay đổi, nhưng clear()không phải vậy const.
Kristopher Johnson

23

Về mặt kỹ thuật, mã của bạn là tốt.

NHƯNG bạn đã viết theo cách làm cho ai đó không biết mã dễ dàng phá vỡ. Đối với c_str (), cách sử dụng an toàn duy nhất là khi bạn chuyển nó dưới dạng tham số cho một hàm. Nếu không, bạn sẽ gặp phải các vấn đề bảo trì.

Ví dụ 1:

{
  std::string server = "my_server";
  std::string name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  //
  // Imagine this is a long function
  // Now a maintainer can easily come along and see name and server
  // and would never expect that these values need to be maintained as
  // const values so why not re-use them

  name += "Martin";
  // Oops now its broken.

  // We use foo
  use_foo(foo);

  // Foo is about to be destroyed, before name and server
}

Vì vậy, để bảo trì, hãy làm rõ ràng:

Giải pháp tốt hơn:

{
  // Now they can't be changed.
  std::string const server = "my_server";
  std::string const name   = "my_name";

  Foo foo;
  foo.server = server.c_str();
  foo.name = name.c_str();

  use_foo(foo);    
}

Nhưng nếu bạn có chuỗi const, bạn không thực sự cần chúng:

{
  char const* server = "my_server";
  char const* name   = "my_name";

  Foo foo;
  foo.server = server;
  foo.name   = name;

  use_foo(foo);
}

ĐỒNG Ý. Vì lý do nào đó bạn muốn chúng dưới dạng chuỗi:
Tại sao không sử dụng chúng chỉ trong cuộc gọi:

{
  std::string server = "my_server";
  std::string name = "my_name";

  // guaranteed not to be modified now!!!     
  use_foo(Foo(server.c_str(), name.c_str());
}

7

Nó có hiệu lực cho đến khi một trong những điều sau xảy ra với stringđối tượng tương ứng :

  • vật thể bị phá hủy
  • đối tượng được sửa đổi

Bạn ổn với mã của mình trừ khi bạn sửa đổi các stringđối tượng đó sau khi các đối tượng c_str()được sao chép vào foonhưng trước đó use_foo()được gọi.


4

Giá trị trả về của c_str () chỉ hợp lệ cho đến khi có lệnh gọi tiếp theo của một hàm thành viên không quan trọng cho cùng một chuỗi


3

Giá trị const char*trả về từ c_str()chỉ có giá trị cho đến khi gọi std::stringđối tượng không phải const tiếp theo . Trong trường hợp này, bạn vẫn ổn vì bạn std::stringvẫn còn trong phạm vi sử dụng trong suốt thời gian tồn tại Foovà bạn không thực hiện bất kỳ thao tác nào khác có thể thay đổi chuỗi trong khi sử dụng foo.


2

Miễn là chuỗi không bị phá hủy hoặc sửa đổi, sử dụng c_str () là OK. Nếu chuỗi được sửa đổi bằng cách sử dụng c_str () được trả về trước đó thì việc triển khai được xác định.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.