c++ - ¿Por qué las referencias const extienden la vida útil de los valores?
standards (2)
¿Por qué el comité de C ++ decidió que las referencias constantes deberían extender la vida útil de los temporales?
Este hecho ya se ha discutido ampliamente en línea, incluso aquí en stackoverflow. El recurso definitivo que explica que este es el caso es probablemente este GoTW:
GotW # 88: un candidato para la "const de más importante"
¿Cuál fue la razón para esta característica del lenguaje? ¿Se sabe?
(La alternativa sería que la vida útil de los temporales no se extienda por ninguna referencia).
Mi propia teoría de la mascota para la razón es que este comportamiento permite a los objetos ocultar los detalles de la implementación. Con esta regla, una función miembro puede cambiar entre devolver un valor o una referencia constante a un valor ya existente internamente sin ningún cambio en el código del cliente. Por ejemplo, una clase de matriz podría devolver vectores de fila y vectores de columna. Para minimizar las copias, una u otra podría devolverse como referencia dependiendo de la implementación (fila mayor frente a columna mayor). Cualquiera que no pueda devolverse por referencia debe devolverse haciendo una copia y devolviendo ese valor (si los vectores devueltos son contiguos). El escritor de la biblioteca puede querer que el margen de maniobra cambie la implementación en el futuro (fila mayor frente a columna mayor) e impida que los clientes escriban código que depende en gran medida de si la implementación es mayor de fila o columna principal. Al pedir a los clientes que acepten valores de retorno como referencia constante, la clase de matriz puede devolver referencias constantes o valores sin ningún cambio en el código del cliente. Independientemente, si se conoce la razón original, me gustaría saberlo.
No estás cuestionando por qué se permite que las referencias const se unan a los temporales, sino simplemente por qué extienden la vida útil de esos temporales.
Considere este código:
struct A
{
void foo() const;
};
A bar();
const A& a = bar();
a.foo(); // (1)
Si la vida útil del temporizador devuelto por bar()
no se extendiera, entonces cualquier uso de a
(ejemplificado por la línea (1)) llevaría a un comportamiento indefinido. Esto haría que las referencias constantes no paramétricas vinculantes a los temporales sean completamente inútiles.
EDITAR (abordando el comentario de OP ):
Por lo tanto, la pregunta real debería ser por qué una variable de referencia constante (que no es un parámetro de función) puede vincularse a un temporal. No conozco la justificación original ( la respuesta de Richard Hodges puede ser la única), pero nos brinda una característica útil. Teniendo en cuenta el siguiente ejemplo:
struct B
{
virtual void foo() const;
};
B bar();
const B& b = bar();
b.foo(); // (1)
La única diferencia de este ejemplo respecto al anterior es que B::foo()
es virtual. Ahora, ¿qué sucede si decidimos introducir una nueva clase D
como una subclase de B
y cambiar el tipo de bar()
de retorno bar()
de B
a D
?
struct B
{
virtual void foo() const;
};
struct D : B
{
virtual void foo() const;
};
//B bar();
D bar();
const B& b = bar();
b.foo(); // This will call D::foo()
// In the end the temporary bound by b will be correctly destroyed
// using the destructor of D.
Por lo tanto, las referencias constantes de enlace a los temporales simplifican el aprovechamiento del polimorfismo dinámico para los objetos que se devuelven por valor.
Se propuso en 1993. Su propósito era eliminar el manejo inconsistente de los temporales cuando están vinculados a referencias.
En aquel entonces, RVO no existía, por lo que simplemente prohibir la vinculación de una referencia temporal a una referencia hubiera sido un éxito de rendimiento.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1993/N0345.pdf