c++ language-lawyer object-lifetime default-arguments reference-binding

c++ - ¿Está bien devolver el valor del argumento predeterminado por referencia constante?



language-lawyer object-lifetime (3)

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 al point(1,4) y al 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 .

¿Está bien devolver el valor del argumento predeterminado por referencia constante como en los ejemplos a continuación:

https://coliru.stacked-crooked.com/a/ff76e060a007723b

#include <string> const std::string& foo(const std::string& s = std::string("")) { return s; } int main() { const std::string& s1 = foo(); std::string s2 = foo(); const std::string& s3 = foo("s"); std::string s4 = foo("s"); }


En su código, tanto s1 como s3 son referencias colgantes. s2 y s4 están bien.

En la primera llamada, el objeto std::string vacío temporal creado a partir del argumento predeterminado se creará en el contexto de la expresión que contiene la llamada. Por lo tanto, morirá al final de la definición de s1 , lo que deja a s1 colgando.

En la segunda llamada, el objeto temporal std::string se usa para inicializar s2 , luego muere.

En la tercera llamada, el literal de cadena "s" se usa para crear un objeto temporal std::string y que también muere al final de la definición de s3 , dejando s3 colgando.

En la cuarta llamada, el objeto temporal std::string con el valor "s" se usa para inicializar s4 y luego muere.

Ver C ++ 17 [class.temporary] /6.1

Un objeto temporal vinculado a un parámetro de referencia en una llamada de función (8.2.2) persiste hasta la finalización de la expresión completa que contiene la llamada.


No es seguro :

En general, la vida útil de un temporal no puede extenderse aún más "pasándola": una segunda referencia, inicializada a partir de la referencia a la que estaba vinculado el temporal, no afecta su vida útil.