Лучший способ вернуть std::string, который является локальным для функции

В С++, каков наилучший способ вернуть функцию 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...???

Ответ 1

Нет. Это неправда. Даже если mystring вышел из сферы действия и уничтожен, ret имеет копию mystring, поскольку функция MyFunc возвращает значение.

Ответ 2

Будет проблема, если ваш код похож:

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).

Ответ 3

Вы пробовали? Строка копируется при ее возврате. Хорошо, что официальная строка, на самом деле копия, вероятно, оптимизирована, но в любом случае она безопасна в использовании.

Ответ 4

Как уже упоминалось, копируется std::string. Таким образом, даже исходная локальная переменная вышла за пределы области действия, вызывающая сторона получает копию std::string.

Я думаю, что чтение на RVO может полностью очистить ваше замешательство. В этом случае он точно упоминается как NRVO (Именованный RVO), но дух тот же.

Чтение бонусов: проблема с использованием RVO заключается в том, что это не самая гибкая вещь в мире. Одним из больших жуков С++ 0x является ссылки rvalue, которые намереваются решить эту проблему.

Ответ 5

Ну, ret будет иметь значение mystring после MyFunc(). В случае возврата результата по значению временный объект создается путем копирования локального.

Что касается меня, есть несколько интересных подробностей о теме в этих разделах С++ FAQ Lite.

Ответ 6

Это зависит от варианта использования. Если экземпляр должен нести ответственность за строку, жало должно быть возвращено ссылкой const. Проблема в том, что делать, если нет объекта для возврата. С указателями недопустимый объект может быть сигнализирован с использованием 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;
}

С уважением, Валентин Хейниц