web-dev-qa-db-ja.com

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

私のプログラムの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()の結果をすぐに別の場所にコピーすることになっていますか?

ありがとうございました。

90
ereOn

_std::string_が破棄された場合、または文字列の非constメンバー関数が呼び出された場合、c_str()の結果は無効になります。そのため、通常、それを保持する必要がある場合は、コピーを作成する必要があります。

あなたの例の場合、c_str()の結果は安全に使用されているようです。なぜなら、そのスコープ内では文字列は変更されないからです。 (ただし、これらの値でuse_foo()または~Foo()が何をしているのかわかりません。文字列を他の場所にコピーする場合、truecopycharポインターをコピーするだけではありません。

80

技術的には、コードは問題ありません。

[〜#〜] but [〜#〜]あなたは、コードを知らない誰かのために簡単に破ることができるような方法で書きました。 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());
}
22
Martin York

対応するstringオブジェクトに次のいずれかが発生するまで有効です。

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

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

7
sharptooth

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

4
DumbCoder

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

3
AJG85

完全を期すために、ここに cppreference.comからの参照と引用 を示します。

c_str()から取得したポインターは、次の方法で無効化できます。

  • 文字列への非const参照を標準ライブラリ関数に渡す、または
  • operator[]at()front()back()begin()rbegin()end()およびrend()を除く、string上の非constメンバー関数の呼び出し。
2

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

2
CharlesB