次のコードは一見無害に見えます。ユーザーはこの関数bar()
を使用して、いくつかのライブラリ機能と対話します。(これはbar()
、一時的でない値または同様のものへの参照を返したので、長い間働いていたかもしれません。)しかし、今では単にの新しいインスタンスを返していますB
。B
繰り返しa()
処理可能な型のオブジェクトへの参照を返す関数がありますA
。B
によって返される一時オブジェクトはbar()
、反復が開始される前に破棄されるため、ユーザーはこのオブジェクトを照会すると、セグメンテーション違反につながります。
誰(ライブラリーまたはユーザー)がこれを責めるかは私は優柔不断です。すべてのライブラリが提供するクラスは私にはきれいに見えますが、確かに他の多くのコードとは何も違いはありません(メンバーへの参照を返す、スタックインスタンスを返すなど)。ユーザーは何も悪いことをしていないように見えます。彼は、オブジェクトの存続期間に関して何もせずにオブジェクトを繰り返し処理しているだけです。
(関連する質問は次のとおりです:ループヘッダー内の複数のチェーンされた呼び出しによって取得されるものに対してコードが「範囲ベースの反復」ではないという一般的なルールを確立する必要があります。右辺値?)
#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;
}
}