std :: string :: c_str () อายุการใช้งานคืออะไร?


100

ในโปรแกรมของฉันฉันต้องเชื่อมต่อกับรหัสเดิมที่ใช้งานconst char*ได้

สมมติว่าฉันมีโครงสร้างที่ดูเหมือน:

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

แอปพลิเคชันระดับสูงกว่าของฉันเกี่ยวข้องเท่านั้นstd::stringดังนั้นฉันจึงคิดที่std::string::c_str()จะใช้เพื่อรับconst char*ตัวชี้กลับ

แต่อายุการใช้งานc_str()คืออะไร?

ฉันสามารถทำสิ่งนี้โดยไม่ต้องเผชิญกับพฤติกรรมที่ไม่ได้กำหนดได้หรือไม่?

{
  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
}

หรือฉันควรจะคัดลอกผลลัพธ์ของc_str()ไปที่อื่นทันที?

ขอบคุณ.


.c_str()ที่เกิดขึ้นกับผมเมื่อผมกำหนดสตริงท้องถิ่นในการทำงานและกลับ ฉันไม่เข้าใจว่าทำไมบางครั้งฉันได้รับเพียงบางส่วนของสตริงจนกว่าฉันจะเข้าใจว่าสิ่งconst char*นั้นไม่ได้อยู่ตลอดไป แต่จนกว่าสตริงจะถูกทำลาย
SomethingSomething

คำตอบ:


85

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

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


ตัวชี้ c_str () อาจไม่ถูกต้องหากออบเจ็กต์ std :: string เป็นอ็อบเจ็กต์อัตโนมัติที่อยู่นอกขอบเขตหรืออยู่ในฟังก์ชันการสร้างเธรด
GuruM

คุณช่วยอธิบายได้non-const member function of the string is called.ไหม?
Mathew Kurian

2
"non-const member function" คือฟังก์ชันสมาชิกใด ๆ ที่ไม่ถูกทำเครื่องหมายด้วยconstคีย์เวิร์ด c_str()ฟังก์ชั่นดังกล่าวอาจเปลี่ยนแปลงเนื้อหาของสายซึ่งในกรณีสตริงอาจจำเป็นต้องจัดสรรหน่วยความจำสำหรับรุ่นโมฆะเป็นสิ้นสุดของสตริงที่ส่งกลับโดย ยกตัวอย่างเช่นsize()และlength()มีconstเพื่อให้คุณสามารถเรียกพวกเขาโดยไม่ต้องกังวลเกี่ยวกับสายการเปลี่ยนแปลง แต่ไม่ได้เป็นclear() const
Kristopher Johnson

23

ในทางเทคนิครหัสของคุณก็ใช้ได้

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

ตัวอย่างที่ 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
}

ดังนั้นสำหรับการบำรุงรักษาให้ชัดเจน:

ทางออกที่ดีกว่า:

{
  // 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);    
}

แต่ถ้าคุณมีสตริง const คุณไม่ต้องการจริงๆ:

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

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

  use_foo(foo);
}

ตกลง. ด้วยเหตุผลบางประการที่คุณต้องการให้เป็นสตริง
ทำไมไม่ใช้เฉพาะในการโทร:

{
  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

ใช้ได้จนกว่าสิ่งใดสิ่งหนึ่งต่อไปนี้จะเกิดขึ้นกับstringวัตถุที่เกี่ยวข้อง:

  • วัตถุถูกทำลาย
  • วัตถุถูกแก้ไข

คุณสบายดีกับรหัสของคุณเว้นแต่คุณจะแก้ไขstringวัตถุเหล่านั้นหลังจากc_str()ที่คัดลอกไปfooแต่ก่อนจะuse_foo()ถูกเรียก


4

ค่าส่งกลับของ c_str () จะใช้ได้จนกว่าจะมีการเรียกฟังก์ชันสมาชิกที่ไม่คงที่สำหรับสตริงเดียวกัน


3

การconst char*ส่งคืนจากc_str()จะใช้ได้จนกว่าจะมีการเรียกใช้std::stringอ็อบเจ็กต์ถัดไปที่ไม่ใช่ const เท่านั้น ในกรณีนี้คุณสบายดีเพราะคุณstd::stringยังอยู่ในขอบเขตของอายุการใช้งานFooและคุณไม่ได้ดำเนินการอื่นใดที่จะเปลี่ยนสตริงในขณะที่ใช้ foo


2

ตราบใดที่สตริงไม่ถูกทำลายหรือแก้ไขการใช้ c_str () ก็ใช้ได้ หากสตริงถูกแก้ไขโดยใช้ c_str () ที่ส่งคืนก่อนหน้านี้จะถูกกำหนดการนำไปใช้งาน


2

เพื่อความสมบูรณ์นี่คือข้อมูลอ้างอิงและใบเสนอราคาจาก cppreference.com :

ตัวชี้ที่ได้รับc_str()อาจไม่ถูกต้องโดย:

  • การส่งผ่านการอ้างอิงที่ไม่ใช่ const ไปยังสตริงไปยังฟังก์ชันไลบรารีมาตรฐานใด ๆ หรือ
  • ฟังก์ชั่นการโทรไม่ใช่สมาชิก const บนstringไม่รวมoperator[], at(), front(), back(), begin(), rbegin(), และend()rend()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.