c++ - texto - la mejor manera de devolver una cadena std:: que local a una función
funciones que retornan valores en c++ (6)
¿Lo has probado? La cadena se copia cuando se devuelve. Bueno, esa es la línea oficial, en realidad la copia probablemente está optimizada, pero de cualquier manera es seguro de usar.
En C ++, ¿cuál es la mejor manera de devolver una función local std :: string variable desde la función?
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...???
Bueno, ret tendrá un valor de mystring después de MyFunc (). En caso de devolver el resultado por valor, un objeto temporal se construye copiando el local.
En cuanto a mí, hay algunos detalles interesantes sobre el tema en estas secciones de C ++ FAQ Lite .
Como se mencionó, la cadena std :: se copia. Así que incluso la variable local original ha quedado fuera del alcance, la persona que llama obtiene una copia de la cadena std :: string.
Creo que leer en RVO puede despejar totalmente tu confusión. En este caso, se lo conoce con precisión como NRVO (llamado RVO) pero el espíritu es el mismo.
Lectura adicional : el problema con el uso de RVO es que no es lo más flexible del mundo. Uno de los grandes rumores de C ++ 0x son las referencias de valor que intentan resolver ese problema.
Depende del caso de uso. Si la instancia debe mantener la responsabilidad de la cadena, las picaduras se deben devolver por referencia constante. El problema es qué hacer si no hay ningún objeto que devolver. Con los punteros, el objeto no válido podría señalizarse utilizando 0. Este "objeto nulo" también podría usarse con referencias (por ejemplo, NullString en el fragmento de código). Una de las mejores formas de indicar un valor de retorno no válido es lanzar excepciones.
Otro caso de uso es si la responsabilidad de la cadena se transfiere a la persona que llama. En este caso debe utilizarse auto_ptr. El siguiente código muestra todos estos casos de uso.
#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;
}
Saludos cordiales, Valentin Heinitz
Habrá un problema si su código es como:
std::string& MyFunc()
{
std::string mystring("test");
return mystring;
}
Entonces, la forma en que lo has escrito está bien. Solo un consejo: si puedes construir una cadena como esta, quiero decir, puedes hacerlo en una fila, a veces es mejor hacerlo así:
std::string MyFunc()
{
return "test";
}
O si es más "complicado", por ej.
std::string MyFunct( const std::string& s1,
const std::string& s2,
const char* szOtherString )
{
return std::string( "test1" ) + s1 + std::string( szOtherString ) + s2;
}
Esto le dará una pista a su compilador para hacer más optimización, por lo que podría hacer una copia menos de su cadena (RVO).
No, eso no es verdad. Incluso si mystring
ha quedado fuera del alcance y se destruye, ret
tiene una copia de mystring ya que la función MyFunc
devuelve por valor.