Il seguente codice sembra piuttosto innocuo a prima vista. Un utente utilizza la funzione bar()
per interagire con alcune funzionalità della libreria. (Questo potrebbe anche aver funzionato per molto tempo da quando ha bar()
restituito un riferimento a un valore non temporaneo o simile.) Ora tuttavia sta semplicemente restituendo una nuova istanza di B
. B
ha di nuovo una funzione a()
che restituisce un riferimento a un oggetto di tipo iterabile A
. L'utente desidera interrogare questo oggetto che porta a un segfault poiché l' B
oggetto temporaneo restituito da bar()
viene distrutto prima dell'inizio dell'iterazione.
Sono indeciso su chi (la biblioteca o l'utente) sia la colpa di questo. Tutte le classi fornite dalla libreria mi sembrano pulite e certamente non stanno facendo nulla di diverso (restituendo riferimenti ai membri, restituendo istanze di stack, ...) rispetto a così tanto altro codice là fuori. L'utente non sembra fare nulla di male, sta solo iterando su un oggetto senza fare nulla riguardo alla vita di quegli oggetti.
(Una domanda correlata potrebbe essere: se si dovesse stabilire la regola generale che il codice non dovrebbe "range-based-for-iterate" su qualcosa che viene recuperato da più di una chiamata concatenata nell'intestazione del ciclo poiché una di queste chiamate potrebbe restituire un rvalue?)
#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;
}
}