Poniższy kod wygląda na pierwszy rzut oka raczej nieszkodliwie. Użytkownik używa tej funkcji bar()
do interakcji z niektórymi funkcjami biblioteki. (Mogło to nawet działać przez długi czas, odkąd bar()
zwróciło odwołanie do wartości nietrwałej lub podobnej.) Teraz jednak zwraca po prostu nową instancję B
. B
ponownie ma funkcję, a()
która zwraca odwołanie do obiektu typu iterowalnego A
. Użytkownik chce wysłać zapytanie do tego obiektu, co prowadzi do uszkodzenia pliku, ponieważ B
zwrócony obiekt tymczasowy bar()
jest niszczony przed rozpoczęciem iteracji.
Jestem niezdecydowany, kto (biblioteka lub użytkownik) jest winien za to. Wszystkie klasy dostarczone mi z biblioteki wyglądają dla mnie na czyste i na pewno nie robią nic innego (zwracanie referencji do członków, zwracanie instancji stosu, ...) niż wiele innych kodów. Wydaje się, że użytkownik nie robi nic złego, po prostu iteruje jakiś obiekt, nie robiąc nic w odniesieniu do jego żywotności.
(Powiązane pytanie może brzmieć: jeśli należy ustanowić ogólną zasadę, że kod nie powinien „opierać się na zakresie iteracji” nad czymś, co jest pobierane przez więcej niż jedno połączenie łańcuchowe w nagłówku pętli, ponieważ każde z tych wywołań może zwrócić wartość?)
#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;
}
}