web-dev-qa-db-fra.com

meilleure façon de renvoyer une chaîne std :: qui local à une fonction

En C++, quelle est la meilleure façon de renvoyer une variable locale std :: string de la fonction?

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

Non, ce n'est pas vrai. Même si mystring est hors de portée et est détruit, ret possède une copie de mystring car la fonction MyFunc renvoie par valeur.

70
Chubsdad

Il y aura un problème si votre code est comme:

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

Donc, la façon dont vous l'avez écrit est OK. Un seul conseil - si vous pouvez construire la chaîne comme ça, je veux dire - vous pouvez le faire sur une seule ligne, il est parfois préférable de le faire comme ceci:

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

Ou si c'est plus "compliqué", par exemple:

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

Cela donnera un indice à votre compilateur pour faire plus d'optimisation, donc il pourrait faire une copie de moins de votre chaîne (RVO).

21
Kiril Kirov

Comme mentionné, la chaîne std :: est copiée. Ainsi, même la variable locale d'origine est hors de portée, l'appelant obtient une copie de la chaîne std ::.

Je pense que la lecture de RVO peut totalement effacer votre confusion. Dans ce cas, il est appelé avec précision NRVO (Named RVO) mais l'esprit est le même.

Lecture bonus : Le problème avec l'utilisation de RVO est que ce n'est pas la chose la plus flexible au monde. L'un des gros bourdonnements de C++ 0x est références rvalue qui vise à résoudre ce problème.

6
kizzx2

L'as tu essayé? La chaîne est copiée lorsqu'elle est retournée. Eh bien, c'est la ligne officielle, en fait, la copie est probablement optimisée, mais de toute façon, elle est sûre à utiliser.

5
Martin Broadhurst

Eh bien, ret aura une valeur de mystring après MyFunc (). En cas de retour du résultat par valeur, un objet temporaire est construit en copiant l'objet local.

Quant à moi, il y a quelques détails intéressants sur le sujet dans ces sections de C++ FAQ Lite .

3
Paul E.

Cela dépend du cas d'utilisation. Si l'instance doit conserver la responsabilité de la chaîne, les piqûres doivent être renvoyées par référence const. Le problème est de savoir quoi faire s'il n'y a pas d'objet à retourner. Avec des pointeurs, l'objet non valide pourrait être signalé à l'aide de 0. Un tel "objet nul" pourrait également être utilisé avec des références (par exemple NullString dans un extrait de code). Une meilleure façon de signaler une valeur de retour non valide est de lever des exceptions.

Un autre cas d'utilisation est si la responsabilité de la chaîne est transférée à l'appelant. Dans ce cas, auto_ptr doit être utilisé. Le code ci-dessous montre tous ces cas d'utilisation.

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

Cordialement, Valentin Heinitz

2
Valentin Heinitz