次のコードでは、文字列はクラスFoo内にカプセル化されています。std :: stringを値で返すのは安全ですか?
Foo :: getText()を呼び出すと、文字列が値で返されます。これにより、文字列オブジェクトの2番目のインスタンスが作成されますが、両方の文字列オブジェクトは現在、ヒープ上の同じcharバッファを指しています。
Fooインスタンスが削除されると、カプセル化された文字列が自動的に破棄され、ヒープ上のcharバッファが削除されます。
getText()
は文字列を値で返しますが、結果として得られる文字列オブジェクトは、元の文字列オブジェクトの存続期間に依然として依存し、相互にポイントするcharバッファを保持します。
これは、retval
の端末への印刷が、すでにヒープ上でフリーになっているメモリへの無効なアクセスであることを意味していませんか?
class Foo
{
Foo(const char* text) :
str(text)
{
}
std::string getText()
{
return str;
}
std::string str;
};
int main()
{
Foo pFoo = new Foo("text");
std::string retval = foo.getText();
delete pFoo;
cout << retval; // invalid memory access to char buffer?
}
は、私は多くの人が列を値によって返されたので、彼らはFooの中の元の文字列の寿命を心配する必要はない、ということを前提と考えます。この問題は厳密には文字列には関係しませんが、実際には破棄時には自由にカプセル化されたポインタを持つクラスに適用されます。しかし、ストリングに関してはここでベストプラクティスは何ですか?
- 文字列を値で返すことはありませんか?
- 元の文字列の有効期間が保証されている場合は、文字列を値で返すだけですか?
- 常に文字列のコピーを作成しますか?
return std::string(retval.c_str());
getText()
の発信者との契約を強制しますか?
EDIT:
は、私はRVOに惑わされたと思います。この例の3つの文字列はすべて、同じアドレスにc_strを返します。 RVOは責任がありますか?
class Obj
{
public:
Obj() : s("text")
{
std::printf("%p\n", s.c_str());
}
std::string getText() { return s; }
std::string s;
};
int main()
{
Obj* pObj = new Obj();
std::string s1(pObj->getText());
std::string s2 = pObj->getText();
delete pObj;
std::printf("%p\n", s1.c_str());
std::printf("%p\n", s2.c_str());
}
結果:
0x600022888
0x600022888
0x600022888
@πάνταῥεῖこれは、 'std :: vector'ではなく' std :: string'に関するものです。もう一つのデュエルミーマーミス。 –
* getText()は値によって文字列を返しますが、結果の文字列オブジェクトは元の文字列オブジェクトの存続期間に依存しており、相互に指し示すcharバッファを保持します。あなたはどこからこれを取得しましたか、またはあなたは推測していますか? C++の仕組みを理解する上でJavaを参考にしているのであれば、C++はJavaではありません。 – PaulMcKenzie
*両方の文字列オブジェクトがヒープ上の同じcharバッファを指すようになりました* - クラスが誤ったまたはコピーされていないコピーコンストラクタ、代入演算子、およびデストラクタを持つ自家製文字列クラスで、次に、同じバッファを指すことができます**誤って**。しかし、専門家と専門家によって書かれた "std :: string"については、正しいコピーセマンティクスを持っています。 – PaulMcKenzie