Std :: Tupleのメンバーが破棄される順序を示すルールはありますか?
たとえば、_Function1
_が_std::Tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>>
_を_Function2
_に返す場合、(_Function2
_のスコープが残っている場合)ClassB
のインスタンスを確認できます最初のメンバーによって参照されるClassA
のインスタンスの前に、2番目のメンバーによって参照されるが破棄されますか?
_std::Tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > Function1()
{
std::Tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > garbage;
get<0>(garbage).reset( /* ... */ );
get<1>(garbage).reset( /* ... */ );
return garbage;
}
void Function2()
{
auto to_be_destroyed = Function1();
// ... do something else
// to_be_destroyed leaves scope
// Is the instance of ClassB destroyed before the instance of ClassA?
}
_
標準では、_std::Tuple
_の破棄の順序は指定されていません。 §20.4.1/ p1が次のように指定しているという事実:
2つの引数を持つタプルのインスタンス化は、同じ2つの引数を持つペアのインスタンス化に似ています。
Similarここではidenticalと解釈されないため、_std::Tuple
_は、その引数の逆破壊順序を持つ必要があります。
_std::Tuple
_の再帰的な性質を考えると、最も可能性が高いのは、破棄の順序が引数の順序と同じであることです。
また、私は GCC BUG 66699 のバグレポートに基づいて仮定を立てています。この議論では、上記の私の仮定は正当化されています。
つまり、_std::Tuple
_の破棄の順序は指定されていません。
あなたの質問に答えて、直接的な答えではなく、私が学んだ人生のレッスンを提供します。
複数の代替案について公式化できる場合、その代替案が標準で義務付けられている理由の合理的な議論-次に、それらのうちのanyが義務付けられていると仮定しないでくださいあります)。
タプルのコンテキストでは、コードを管理する人に親切にしてください。タプル要素の破棄順序が他の要素の破棄を混乱させる可能性がないようにしてください。それはただの悪です...このことをデバッグする必要がある不幸なプログラマーを想像してみてください。実際、その貧しい魂は、あなたが過去からの賢いトリックをすでに忘れていた数年後にはあなた自身であるかもしれません。
破壊の順序に完全に依存する必要がある場合は、タプルの要素をデータメンバーとして適切なクラスを使用している必要があります(デストラクタを記述して、どの順序で何が発生する必要があるかを明確にすることができます)。破壊のより明確な制御を容易にする取り決め。
Clang 3.4では、std::pair
と2つの要素std::Tuple
の両方で同じ破壊順序が得られ、g ++ 5.3では、主にlibstd ++でのstd::Tuple
の再帰的な実装が原因である逆の順序が得られます。
だから、基本的にはコメントで言ったことに要約すると、実装定義です。
[〜#〜] bug [〜#〜] レポートから:
Martin Seborによるコメント
Std :: pairメンバーのレイアウトは完全に指定されているため、初期化と破棄の順序も同様です。テストケースの出力は、この順序を反映しています。
Std:stupleサブオブジェクトの初期化(および破棄)の順序は、あまり明確に指定されていません。少なくとも、特定の注文が必要かどうかは、仕様を読んでもすぐにはわかりません。
Libstdc ++でのstd :: Tupleの出力がstd :: pairの逆である理由は、再帰的な継承に依存する実装が、タプル要素を逆の順序で格納および構築するためです。つまり、最後の要素が最初に格納および構築され、その後に各派生クラスが続きます(それぞれに最後の-N番目の要素が格納されます).
バグ報告者が引用している標準[セクション20.4.1]からの引用
1この節では、任意の数の引数でインスタンス化できるクラステンプレートTupleとしてTuple型を提供するTupleライブラリについて説明します。各テンプレート引数は、タプル内の要素のタイプを指定します。その結果、タプルは、異種の固定サイズの値のコレクションです。 2つの引数を持つタプルのインスタンス化は、同じ2つの引数を持つペアのインスタンス化に似ています。 20.3を参照してください。
リンクされたバグで行われたこれに対する議論は次のとおりです。
類似していると説明されていても、細部が同じであるとは限りません。 std :: pairとstd :: Tupleは、それぞれに異なる要件を持つ別個のクラスです。この点で同じように動作する必要がある(つまり、サブオブジェクトが同じ順序で定義されている)必要があると思われる場合は、それを保証する特定の表現を指す必要があります。