返回本地函数的std :: string的最好方法
在C ++中,从函数返回函数本地std :: stringvariables的最佳方法是什么?
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
仍然有一个mystring的副本,作为函数MyFunc
按值返回。
如果你的代码是这样的,会有一个问题:
std::string& MyFunc() { std::string mystring("test"); return mystring; }
所以,你写的方式是可以的。 只是一个build议 – 如果你能像这样构buildstring,我的意思是说 – 你可以做到一行,有时候这样做更好:
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; }
这会给你的编译器一个提示 ,做更多的优化,所以它可以做一个你的string(RVO)的副本。
你试过了吗? 该string在返回时被复制。 那么这是官方的线,实际上副本可能优化了,但无论哪种方式是安全的使用。
如上所述,std :: string被复制。 所以即使原来的局部variables超出了范围,调用者也得到了std :: string的一个副本。
我认为阅读RVO可以完全清除您的困惑。 在这种情况下,它被精确地称为NRVO(命名RVO),但精神是相同的。
奖金阅读 :使用RVO的问题在于它不是世界上最灵活的东西。 C ++ 0x的一个很大的嗡嗡声是右值引用 ,意图解决这个问题。
那么ret在MyFunc()之后会有一个mystring的值。 在通过值返回结果的情况下通过复制本地构造一个临时对象。
至于我,在C ++ FAQ Lite的这些部分有一些关于这个主题的有趣的细节。
这取决于用例。 如果实例应该对string保持责任,应该通过const引用返回stings。 问题是,如果没有对象返回,该怎么办。 使用指针无效对象可以使用0来指示。这样的“空对象”也可以用于引用(例如代码片段中的空string)。 因为更好的方式来表示无效的返回值是抛出exception。
另一个用例是如果将string的责任传递给调用者。 在这种情况下,应该使用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; }
最好的问候,瓦伦丁Heinitz