El siguiente código parece bastante inofensivo a primera vista. Un usuario utiliza la función bar()
para interactuar con algunas funciones de la biblioteca. (Esto incluso puede haber funcionado durante mucho tiempo desde que bar()
devolvió una referencia a un valor no temporal o similar). Ahora, sin embargo, simplemente está devolviendo una nueva instancia de B
. B
nuevamente tiene una función a()
que devuelve una referencia a un objeto del tipo iterable. A
. El usuario desea consultar este objeto, lo que conduce a un fallo de seguridad, ya que el objeto B
devuelto por bar()
se destruye antes de que comience la iteración.
Soy indeciso a quien (la biblioteca o el usuario) tiene la culpa de esto. Todas las clases proporcionadas por la biblioteca me parecen limpias y ciertamente no hacen nada diferente (devolviendo referencias a miembros, devolviendo instancias de pila, ...) de lo que muchos otros códigos hacen. El usuario no parece hacer nada malo también, solo está iterando sobre un objeto sin hacer nada con respecto a la vida útil de los objetos.
(Una pregunta relacionada podría ser: ¿Debería establecerse la regla general de que el código no debería "basado en rango para iteración" sobre algo que se recupera mediante más de una llamada encadenada en el encabezado del bucle ya que cualquiera de estas llamadas? podría devolver un valor?)
#include <algorithm>
#include <iostream>
// "Library code"
struct A
{
A():
v{0,1,2}
{
std::cout << "A()" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
int * begin()
{
return &v[0];
}
int * end()
{
return &v[3];
}
int v[3];
};
struct B
{
A m_a;
A & a()
{
return m_a;
}
};
B bar()
{
return B();
}
// User code
int main()
{
for( auto i : bar().a() )
{
std::cout << i << std::endl;
}
}