Der folgende Code sieht auf den ersten Blick ziemlich harmlos aus. Ein Benutzer verwendet die Funktion, bar()
um mit einigen Bibliotheksfunktionen zu interagieren. (Möglicherweise hat dies sogar schon lange funktioniert, nachdem bar()
ein Verweis auf einen nicht temporären Wert oder Ähnliches zurückgegeben wurde.) Jetzt wird jedoch einfach eine neue Instanz von zurückgegeben B
. B
hat wieder eine Funktion a()
, die einen Verweis auf ein Objekt des iterierbaren Typs zurückgibt A
. Der Benutzer möchte dieses Objekt abfragen, was zu einem Segfault führt, da das von zurückgegebene temporäre B
Objekt bar()
zerstört wird, bevor die Iteration beginnt.
Ich bin mir nicht sicher, wer (Bibliothek oder Benutzer) dafür verantwortlich ist. Alle von der Bibliothek bereitgestellten Klassen sehen für mich sauber aus und machen auf keinen Fall etwas anderes (Rückgabe von Verweisen auf Mitglieder, Rückgabe von Stack-Instanzen, ...) als so viel anderer Code da draußen. Der Benutzer scheint auch nichts falsch zu machen, er iteriert nur über ein Objekt, ohne irgendetwas in Bezug auf die Lebensdauer dieses Objekts zu tun.
(Eine verwandte Frage könnte sein: Sollte man die allgemeine Regel festlegen, dass Code nicht "bereichsbasiert für Iteration" über etwas sein sollte, das von mehr als einem verketteten Aufruf im Loop-Header abgerufen wird, da einer dieser Aufrufe u. U. a. Zurückgibt rWert?)
#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;
}
}