webentwicklung-frage-antwort-db.com.de

beste Weg, um einen std :: string, der lokal zu einer Funktion ist, zurückzugeben

Was ist in C++ der beste Weg, um eine funktionlokale std :: string-Variable von der Funktion zurückzugeben?

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...???
50
Tony The Lion

Nein, das ist nicht wahr. Selbst wenn mystring den Gültigkeitsbereich verlassen hat und zerstört wird, hat ret eine Kopie von mystring, da die Funktion MyFunc nach Wert zurückgibt.

70
Chubsdad

Es wird ein Problem geben, wenn Ihr Code wie folgt lautet:

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

So, wie du es geschrieben hast, ist es in Ordnung. Nur ein Ratschlag - wenn Sie die Zeichenkette so konstruieren können, meine ich - Sie können es in einer Reihe tun, manchmal ist es besser, es so zu tun:

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

Oder wenn es "komplizierter" ist, zum Beispiel:

std::string MyFunct( const std::string& s1, 
                     const std::string& s2, 
                     const char* szOtherString )
{
    return std::string( "test1" ) + s1 + std::string( szOtherString ) + s2;
}

Dies gibt Ihrem Compiler einen Hinweis, um weitere Optimierungen vorzunehmen, sodass eine Kopie Ihres Strings (RVO) weniger erstellt werden kann.

21
Kiril Kirov

Wie bereits erwähnt, wird der std :: string kopiert. Selbst wenn die ursprüngliche lokale Variable den Gültigkeitsbereich verlässt, erhält der Aufrufer eine Kopie der std :: string.

Ich denke, das Lesen von RVO kann Ihre Verwirrung völlig beseitigen. In diesem Fall wird es genau als NRVO (Named RVO) bezeichnet, aber der Geist ist der gleiche.

Bonuslesung : Das Problem bei der Verwendung von RVO ist, dass es nicht die flexibelste Sache der Welt ist. Einer der großen Pluspunkte von C++ 0x ist rvalue references , mit dem dieses Problem gelöst werden soll.

6
kizzx2

Hast du es versucht? Die Zeichenfolge wird bei der Rückgabe kopiert. Nun, das ist die offizielle Zeile, eigentlich ist die Kopie wahrscheinlich wegoptimiert, aber so oder so ist es sicher zu benutzen.

5

Nun, ret hat nach MyFunc () den Wert mystring. Wenn das Ergebnis als Wert zurückgegeben wird, wird ein temporäres Objekt durch Kopieren des lokalen Objekts erstellt.

Für mich gibt es einige interessante Details zum Thema in diesen Abschnitten von C++ FAQ Lite .

3
Paul E.

Es hängt vom Anwendungsfall ab. Wenn die Instanz die Verantwortung für die Zeichenfolge behalten soll, sollten die Zeichenfolgen durch einen konstanten Verweis zurückgegeben werden. Das Problem ist, was zu tun ist, wenn es kein Objekt gibt, das zurückgegeben werden kann. Mit Zeigern könnte das ungültige Objekt mit 0 signalisiert werden. Ein solches "Null-Objekt" könnte auch mit Referenzen verwendet werden (z. B. NullString im Codeausschnitt). Eine bessere Möglichkeit, einen ungültigen Rückgabewert anzuzeigen, besteht darin, Ausnahmen auszulösen.

Ein weiterer Anwendungsfall ist, wenn die Verantwortung für die Zeichenfolge auf den Aufrufer übertragen wird. In diesem Fall sollte auto_ptr verwendet werden. Der folgende Code zeigt alle diese Anwendungsfälle.

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

Viele Grüße Valentin Heinitz

2