C++では、関数から関数ローカルstd :: string変数を返す最良の方法は何ですか?
std::string MyFunc()
{
std::string mystring("test");
return mystring;
}
std::string ret = MyFunc(); // ret has no value because mystring has already gone out of scope...???
いいえ、そうではありません。 mystring
がスコープ外に出て破棄された場合でも、ret
は関数MyFunc
が値で返すためmystringのコピーを持っています。
コードが次のような場合、問題が発生します。
std::string& MyFunc()
{
std::string mystring("test");
return mystring;
}
だから、あなたが書いた方法は大丈夫です。 1つのアドバイス-このような文字列を作成できる場合、つまり-1行で実行できる場合は、次のようにすることをお勧めします。
std::string MyFunc()
{
return "test";
}
または、より複雑な場合、たとえば:
std::string MyFunct( const std::string& s1,
const std::string& s2,
const char* szOtherString )
{
return std::string( "test1" ) + s1 + std::string( szOtherString ) + s2;
}
これにより、コンパイラにhintが与えられ、より最適化が行われるため、文字列(RVO)のコピーが1つ少なくなります。
前述のように、std :: stringがコピーされます。したがって、元のローカル変数が範囲外になった場合でも、呼び出し元はstd :: stringのコピーを取得します。
[〜#〜] rvo [〜#〜] を読むと混乱を完全に解消できると思います。この場合、正確にはNRVO(RVOという名前)と呼ばれますが、その精神は同じです。
ボーナスリーディング:RVOを使用することの問題は、RVOが世界で最も柔軟なものではないことです。 C++ 0xの大きな話題の1つは、 右辺値参照 で、この問題を解決しようとしています。
試しましたか?文字列は、返されるときにコピーされます。まあそれは公式の行です、実際にはコピーはおそらく最適化されて離れていますが、どちらの方法でも安全に使用できます。
さて、retはMyFunc()の後にmystringの値を持ちます。値で結果を返す場合、ローカルオブジェクトをコピーして一時オブジェクトが作成されます。
私に関しては、これらのセクションのトピックに関する興味深い詳細が C++ FAQ Lite にあります。
ユースケースに依存します。インスタンスが文字列の責任を保持する必要がある場合、const参照によってスティングが返されます。問題は、返すオブジェクトがない場合の対処方法です。ポインターを使用すると、0を使用して無効なオブジェクトを通知できます。このような「null-object」は、参照(コードスニペットのNullStringなど)でも使用できます。無効な戻り値を通知するより良い方法は、例外をスローすることです。
別の使用例は、文字列の責任が呼び出し元に転送される場合です。この場合、auto_ptrを使用する必要があります。以下のコードは、このすべてのユースケースを示しています。
#include <string>
#include <memory> //auto_ptr
#include <iostream>
using std::string;
using std::auto_ptr;
using std::cout;
using std::endl;
static const string NullString("NullString\0");
///// Use-Case: GETTER //////////////////
//assume, string should be found in a list
// and returned by const reference
//Variant 1: Pseudo null object
const string & getString( bool exists ) {
//string found in list
if( exists ) {
static const string str("String from list");
return str;
}
//string is NOT found in list
return NullString;
}
//Variant 2: exception
const string & getStringEx( bool available ) {
//string found in list
if( available ) {
static const string str("String from list");
return str;
}
throw 0; //no valid value to return
}
///// Use-Case: CREATER /////////////////
auto_ptr<string> createString( bool ok )
{
if( ok ){
return auto_ptr<string>(new string("A piece of big text"));
}else{
return auto_ptr<string>();
}
}
int main(){
bool ok=true, fail=false;
string str;
str = getString( ok );
cout << str << ", IsNull:"<<( str == NullString )<<endl;
str = getString( fail );
cout << str << ", IsNull:"<<( str == NullString )<<endl;
try{
str = getStringEx( ok );
cout << str <<endl;
str = getStringEx( fail );
cout << str <<endl; //line won't be reached because of ex.
}
catch (...)
{
cout << "EX: no valid value to return available\n";
}
auto_ptr<string> ptext = createString( ok );
if ( ptext.get() ){
cout << *ptext << endl;
} else {
cout << " Error, no text available"<<endl;
}
ptext = createString( fail );
if ( ptext.get() ){
cout << *ptext << endl;
} else {
cout << " Error, no text available"<<endl;
}
return 0;
}
よろしく、バレンティン・ハイニッツ