Depende de lo que hagas con la cuerda después.
Si su pregunta es ¿ es correcto mi código? entonces sí lo es.
De [dcl.fct.default] / 2
[ Ejemplo : la declaración
void point(int = 3, int = 4);
declara una función que se puede llamar con cero, uno o dos argumentos de tipo int. Se puede llamar de cualquiera de estas formas:
point(1,2); point(1); point();
Las dos últimas llamadas son equivalentes a point(1,4)
y point(3,4)
, respectivamente. - ejemplo final ]
Entonces su código es efectivamente equivalente a:
const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));
Todo su código es correcto, pero no hay extensión de duración de referencia en ninguno de estos casos, ya que el tipo de retorno es una referencia.
Como llama a una función con un carácter temporal, la vida útil de la cadena devuelta no extenderá la instrucción.
const std::string& s1 = foo(std::string("")); // okay
s1; // not okay, s1 is dead. s1 is the temporary.
Su ejemplo con s2
está bien ya que copia (o mueve) desde el temporal antes del final del satement. s3
tiene el mismo problema que s1
.
std::string
con una clase propia para que pueda rastrear la construcción y la destrucción.