std :: string :: c_str()ライフタイムとは何ですか?


100

私のプログラムの1つでは、で動作するいくつかのレガシーコードとやり取りする必要があり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ポインタを。)


std :: stringオブジェクトがスコープ外になっているか、スレッド作成関数の呼び出し中の自動オブジェクトである場合、c_str()ポインターは無効になる可能性があります。
GuruM 2012年

説明していただけますnon-const member function of the string is called.か?
Mathew Kurian

2
「非constメンバー関数」は、constキーワードでマークされていないメンバー関数です。このような関数は、文字列の内容を変更する場合があります。その場合、文字列は、によって返される文字列のnullで終了するバージョンのメモリを再割り当てする必要がある場合がありますc_str()。たとえば、size()length()しているconstあなたが変える、文字列を気にせずにそれらを呼び出すことができますので、しかし、clear()ではありませんconst
クリストファージョンソン

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

OK。何らかの理由で、それらを文字列として使用する必要があります。
使用し呼び出しでのみ使用しないでください。

{
  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オブジェクトに次のいずれかが発生するまで有効です。

  • オブジェクトは破棄されます
  • オブジェクトが変更された

sがコピーされてから呼び出される前にこれらのstringオブジェクトを変更しない限り、コードは問題ありません。c_str()foouse_foo()


4

c_str()の戻り値は、同じ文字列に対する非定数メンバー関数の次の呼び出しまでのみ有効です


3

const char*からの戻り値c_str()は、std::stringオブジェクトへの次の非const呼び出しまでのみ有効です。この場合、あなたstd::stringのライフタイムはまだスコープ内にあり、Foofooの使用中に文字列を変更する他の操作を行っていないため、問題はありません。


2

文字列が破壊または変更されない限り、c_str()の使用は問題ありません。以前に返されたc_str()を使用して文字列が変更された場合、実装で定義されます。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.