лучший способ вернуть std :: string, локальный для функции - PullRequest
50 голосов
/ 20 октября 2010

В 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...???

Ответы [ 6 ]

70 голосов
/ 20 октября 2010

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

21 голосов
/ 20 октября 2010

Будет проблема, если ваш код будет выглядеть так:

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

6 голосов
/ 20 октября 2010

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

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

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

5 голосов
/ 20 октября 2010

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

3 голосов
/ 20 октября 2010

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

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

2 голосов
/ 20 октября 2010

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

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

...