It depends on the use case. If an instance should keep responsibility for a string, strings should be returned by a const reference. The problem is, what to do, if there isn't any object to return. With pointers, the invalid object could be signaled using 0. Such a "null-object" could be also used with references (e.g., NullString in the code snippet).
Of course, a better way to signal an invalid return value is throwing exceptions.
Another use case is if the responsibility for the string is transferred to the caller. In this case auto_ptr should be used. The code below shows all this use cases.
#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; }