Apa itu std :: string :: c_str () seumur hidup?

100

Di salah satu program saya, saya harus berinteraksi dengan beberapa kode lama yang berfungsi const char*.

Katakanlah saya memiliki struktur yang terlihat seperti:

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

Aplikasi tingkat tinggi saya hanya berurusan dengan std::string, jadi saya berpikir untuk menggunakan std::string::c_str()untuk mendapatkan const char*petunjuk kembali .

Tapi untuk apa seumur hidup c_str()?

Bisakah saya melakukan sesuatu seperti ini tanpa menghadapi perilaku yang tidak ditentukan?

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

Atau apakah saya harus segera menyalin hasil dari c_str()ke tempat lain?

Terima kasih.

ereOn
sumber
Terjadi pada saya ketika saya mendefinisikan string lokal dalam sebuah fungsi dan kembali .c_str(). Saya tidak mengerti mengapa kadang-kadang saya hanya mendapatkan bagian dari string, sampai saya mengerti bahwa const char*itu tidak hidup selamanya, tetapi sampai string itu hancur
SomethingSomething

Jawaban:

85

The c_str()hasil menjadi tidak valid jika std::stringhancur atau jika fungsi anggota non-const string disebut. Jadi, biasanya Anda ingin membuat salinannya jika Anda perlu menyimpannya.

Dalam kasus contoh Anda, tampaknya hasil dari c_str()digunakan dengan aman, karena string tidak diubah saat berada dalam cakupan itu. (Namun, kami tidak tahu apa use_foo()atau ~Foo()mungkin akan dilakukan dengan nilai-nilai itu; jika mereka menyalin string di tempat lain, maka mereka harus melakukan salinan yang sebenarnya , dan tidak hanya menyalin charpetunjuknya.)

Kristopher Johnson
sumber
c_str () pointer bisa jadi tidak valid jika objek std :: string adalah objek otomatis yang keluar dari ruang lingkup atau dalam panggilan ke fungsi pembuatan thread.
GuruM
Bisakah Anda menjelaskan non-const member function of the string is called.?
Mathew Kurian
2
Sebuah "fungsi anggota non-const" adalah fungsi anggota yang tidak ditandai dengan constkata kunci. Fungsi seperti itu mungkin mengubah konten string, dalam hal ini string mungkin perlu mengalokasikan kembali memori untuk versi string yang dihentikan null yang dikembalikan oleh c_str(). Misalnya, size()dan length()are const, sehingga Anda dapat memanggilnya tanpa khawatir stringnya berubah, padahal clear()sebenarnya tidak const.
Kristopher Johnson
23

Secara teknis kode Anda baik-baik saja.

TETAPI Anda telah menulis sedemikian rupa sehingga mudah dibobol bagi seseorang yang tidak tahu kodenya. Untuk c_str () satu-satunya penggunaan yang aman adalah ketika Anda meneruskannya sebagai parameter ke suatu fungsi. Jika tidak, Anda membuka diri terhadap masalah pemeliharaan.

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

Jadi untuk pemeliharaan jelaskan:

Solusi yang lebih baik:

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

Tetapi jika Anda memiliki string const, Anda sebenarnya tidak membutuhkannya:

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

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

  use_foo(foo);
}

BAIK. Untuk beberapa alasan Anda menginginkannya sebagai string:
Mengapa tidak menggunakannya hanya dalam panggilan:

{
  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());
}
Martin York
sumber
7

Ini valid hingga salah satu hal berikut terjadi pada stringobjek yang sesuai :

  • benda itu hancur
  • objek diubah

Anda baik-baik saja dengan kode Anda kecuali Anda memodifikasi stringobjek tersebut setelah c_str()s disalin ke footetapi sebelum use_foo()dipanggil.

gigi tajam
sumber
4

Nilai kembali dari c_str () hanya berlaku sampai panggilan berikutnya dari fungsi anggota tidak tetap untuk string yang sama

DumbCoder
sumber
3

Hasil const char*dari c_str()hanya valid hingga panggilan non-const berikutnya ke std::stringobjek. Dalam hal ini Anda baik-baik saja karena Anda std::stringmasih dalam lingkup seumur hidup Foodan Anda tidak melakukan operasi lain yang akan mengubah string saat menggunakan foo.

AJG85
sumber
2

Selama string tidak dihancurkan atau diubah, menggunakan c_str () tidak masalah. Jika string dimodifikasi menggunakan c_str () yang dikembalikan sebelumnya implementasi didefinisikan.

CharlesB
sumber
2

Untuk kelengkapannya, berikut referensi dan kutipan dari cppreference.com :

Pointer yang diperoleh dari c_str()mungkin tidak valid oleh:

  • Meneruskan referensi non-const ke string ke fungsi library standar apa pun, atau
  • Memanggil fungsi anggota non-const pada string, tidak termasuk operator[], at(), front(), back(), begin(), rbegin(), end()dan rend().
Victor Sergienko
sumber