返回函数本地的std :: string的最佳方法

时间:2010-10-20 10:42:03

标签: c++ return-value

在C ++中,从函数返回函数local 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...???

7 个答案:

答案 0 :(得分:69)

没有。事实并非如此。即使mystring超出范围并被销毁,ret也有一个mystring副本,因为函数MyFunc按值返回。

答案 1 :(得分:21)

如果您的代码如下,则会出现问题:

std::string& MyFunc()
{
    std::string mystring("test");
    return mystring;
}

所以,你写它的方式还可以。只有一个建议 - 如果你能构建这样的字符串,我的意思是 - 你可以在一行中完成它,有时候这样做更好:

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

这将为编译器提供提示以进行更多优化,因此它可以减少一个字符串副本(RVO)。

答案 2 :(得分:6)

如上所述,复制了std :: string。因此,即使原始局部变量超出范围,调用者也会获得std :: string的副本。

我认为阅读RVO可以完全清除你的困惑。在这种情况下,它被准确地称为NRVO(命名为RVO),但精神是相同的。

奖金阅读:使用RVO的问题在于它不是世界上最灵活的东西。 C ++ 0x的一大嗡嗡声是rvalue references,它打算解决这个问题。

答案 3 :(得分:5)

你试过吗? 返回时会复制该字符串。 那么这是官方的,实际上副本可能已经过优化,但无论哪种方式都可以安全使用。

答案 4 :(得分:3)

嗯,在MyFunc()之后,ret将具有mystring值。如果按值返回结果,则通过复制本地对象来构造临时对象。

至于我,C++ FAQ Lite的这些部分中有关于该主题的一些有趣的细节。

答案 5 :(得分:2)

这取决于用例。如果实例应该对字符串负责,则应该通过const引用返回stings。问题是,如果没有要返回的对象,该怎么办。使用指针,可以使用0来发信号通知无效对象。这样的“空对象”也可以与引用一起使用(例如,代码片段中的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;
}

祝你好运, Valentin Heinitz

答案 6 :(得分:2)

之前的答案都没有包含关键概念。这个概念是移动语义std::string 类具有 move 构造函数,这意味着它具有移动语义移动语义意味着在函数返回时不会将对象复制到不同的位置,从而提供更快的函数执行时间。

尝试单步调试返回 std::string 的函数并检查即将返回的对象的内部结构。您将看到成员字段指针地址 xxx。然后,检查接收函数返回值的 std::string 变量。您将在该对象中看到相同的指针地址 xxx

这意味着,女士们,先生们,没有发生复制。这是移动语义,上帝保佑美国!