Наступний код на перший погляд виглядає досить нешкідливим. Користувач використовує функцію bar()
для взаємодії з деякими функціями бібліотеки. (Це, можливо, навіть давно працювало, оскільки bar()
повернуло посилання на тимчасове значення чи подібне.) Однак це просто повернення нового екземпляра B
. B
знову має функцію, a()
яка повертає посилання на об'єкт ітеративного типу A
. Користувач хоче запитувати цей об'єкт, що призводить до сегмента за замовчуванням, оскільки тимчасовий B
об'єкт, повернутий тим bar()
, знищується до початку ітерації.
Я нерішучий, хто (бібліотека чи користувач) винен у цьому. Усі класи, що надаються бібліотекою, мені виглядають чистими, і, звичайно, не роблять нічого іншого (повертаючи посилання на членів, повертаючи екземпляри стека, ...), ніж стільки іншого коду там. Користувач, здається, також не робить нічого поганого, він просто повторюється над яким-небудь об'єктом, не роблячи нічого, що стосується цих об'єктів.
(Пов'язане запитання може бути: чи слід встановити загальне правило, що код не повинен "базуватися на ітерації" для чогось, що отримується більш ніж одним ланцюговим викликом у заголовку циклу, оскільки будь-який з цих викликів може повернути a оцінювати?)
#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;
}
}