5

次のコードを検討してください。

#include <iostream>

struct A {
  ~A() { std::cout << "~A" << std::endl; }
};

struct B {
  ~B() { std::cout << "~B" << std::endl; }
};

struct C {
  ~C() { std::cout << "~C" << std::endl; }

  void operator<<(const B &) {}
};

C f(const A &a = A()) {
  return C();
}

int main() {
  f(A()) << B();
}

GCC でコンパイルして実行すると、次の出力が得られます。

~C
~A
~B

他のコンパイラでコンパイルしたときに、タイプ A、B、および C の一時オブジェクトのデストラクタがこの順序で呼び出されることが保証されていますか? 一般に、一時的なものがある場合、デストラクタ呼び出しの順序は何ですか?

4

3 に答える 3

10

部分式とその順序付けについて話しましょう。がの前にシーケンスされている場合、 E1isの前に完全に評価する必要があることを意味します。が で順序付けされていない場合、それは任意の順序で評価されることを意味します。 E2E1E2E1 E2E1E2

についてf(A()) << B()は、あなたの場合は と同じですがf(A()).operator<<(B())、次のことがわかっています。

  • A()の前に配列されf(...)
  • f(...)の前に配列されoperator<<
  • B()前に配列されますoperator<<

これは、次のことも示しています。

  • A()前に配列されますoperator<<
  • A()でシーケンスされていませんB()
  • f(...)でシーケンスされていませんB()

複雑にならないように RVO を仮定すると、コンパイラが部分式を評価できる順序は次のようになります。

  • A()-> f(...)-> B()、降伏~B()-> ~C()->~A()
  • A()-> B()-> f(...)、降伏~C()-> ~B()->~A()
  • B()-> A()-> f(...)、降伏~C()-> ~A()->~B()

後者は、OP で観察される順序です。破壊の順序は常に構築の逆順であることに注意してください。

于 2012-12-11T16:10:18.803 に答える
3

式の評価順序はf(A()) << B();指定されていません。したがって、建設/破壊の順序も指定されていません。

于 2012-12-11T15:54:01.233 に答える
2

のオペランドの評価順序は規定され<<ていません。したがって、順序は保証されません。短絡演算子&&||、三項演算子?:、およびコンマ,演算子のみが、オペランドの評価順序が明確に定義されています。その他の場合、左のオペランドを右のオペランドの前に評価する必要はありません (またはその逆)。

さらに、演算子の優先順位または結合性を評価の順序と混同しないでください。特定の式に対してE1 op E2、演算子opが適用される前に、 と の両方E1E2評価する必要があるだけですが、それらの間でE1E2を任意の順序で評価できます。

のように式に複数の演算子がある場合、優先順位規則によって演算子が適用される順序が決定されE1 op1 E2 op2 E3ます。

結合性は、同じ演算子が複数回使用されている場合、つまり で、またはE1 op E2 op E3として解釈される場合に、どのオペランドがどの演算子にバインドされるかを決定するために使用されます。(E1 op E2) op E3E1 op (E2 op E3)

于 2012-12-11T15:54:17.123 に答える