14

C ++標準では、例外仕様を持つ仮想関数について次のように規定されています。

仮想関数に例外仕様がある場合、派生クラスのその仮想関数をオーバーライドする関数の定義を含むすべての宣言は、基本クラスの仮想関数(C +)の例外仕様によって許可される例外のみを許可するものとします。 +03§15.4/3)。

したがって、次の形式は正しくありません。

struct B {
    virtual void f() throw() { } // allows no exceptions
};
struct D : B {
    virtual void f() { }         // allows all exceptions
};

(1)このルールはデストラクタに適用されますか?つまり、次は整形式ですか?

struct B {
    virtual ~B() throw() { }
};
struct D : B {
    virtual ~D() { }
};

(2)このルールは、暗黙的に宣言されたデストラクタにどのように適用されますか?つまり、次は整形式ですか?

struct B {
    virtual ~B() throw() { }
};
struct D : B { 
    // ~D() implicitly declared
};

一般的なケースでは、例外仕様を記述してはなりませんstd::exceptionが、デストラクタは仮想であり、空の例外仕様があるため、この質問には実際的な影響があります。

デストラクタから例外がスローされないようにすることをお勧めします。例を簡略化するために、デストラクタがすべての例外を許可する(つまり、例外指定がない)か、例外を許可しない(つまり、空の例外仕様があります)。

4

1 に答える 1

14

(1)このルールはデストラクタに適用されますか?

はい、このルールはデストラクタに適用されます(デストラクタのルールに例外はありません)。したがって、この例は形式が正しくありません。整形式にするために、の例外仕様は、たとえば、の例外仕様~D()と互換性がある必要があります。~B()

struct B {
    virtual ~B() throw() { }
};
struct D : B {
    virtual ~D() throw() { }
};

(2)このルールは、暗黙的に宣言された特殊メンバー関数にどのように適用されますか?

C ++標準では、暗黙的に宣言された特殊メンバー関数について次のように述べています。

暗黙的に宣言された特殊メンバー関数には、例外仕様が必要です。

f暗黙的に宣言されたデフォルトコンストラクタ、コピーコンストラクタ、デストラクタ、またはコピー代入演算子である場合、その暗黙の例外仕様は、の暗黙の定義によって直接呼び出される関数の例外仕様で許可されているT場合にのみ、タイプIDを指定します。Tf

f直接呼び出す関数がすべての例外を許可する場合はすべての例外を許可し、直接呼び出すすべての関数が例外を許可しない場合は例外を許可しfない(C++03§15.4/13)。

暗黙的に宣言されたデストラクタによって直接呼び出される関数は何ですか?

デストラクタの本体を実行し、本体内に割り当てられた自動オブジェクトを破棄した後、クラスのデストラクタはX呼び出します

  • Xの直接メンバーのデストラクタ、
  • Xの直接基本クラスのデストラクタと、
  • Xが最も派生したクラスのタイプである場合、そのデストラクタはXの仮想基本クラスのデストラクタを呼び出します

(C++03§12.4/6;読みやすくするために再フォーマットされています)。

したがって、暗黙的に宣言されたデストラクタには、これらのデストラクタのいずれかによって許可される例外を許可する例外仕様があります。質問の例を検討するには:

struct B {
    virtual ~B() throw() { }
};
struct D : B { 
    // ~D() implicitly declared
};

暗黙的に宣言されたによって呼び出される唯一のデストラクタ~D()はです~B()~B()は例外を許可しないので、例外を許可せず、~D()宣言されたかのようになりvirtual ~D() throw()ます。

この例外仕様は明らかに'sと互換性が~B()あるため、この例は整形式です。


これが重要である理由の実際的な例として、次のことを考慮してください。

struct my_exception : std::exception {
    std::string message_;
};

~string()すべての例外を許可するため、暗黙的に宣言されたもの~my_exception()はすべての例外を許可します。基本クラスのデストラクタ~exception()は仮想であり、例外を許可しないため、派生クラスのデストラクタは基本クラスのデストラクタと互換性がなく、形式が正しくありません。

この例を整形式にするために、空の例外仕様を使用してデストラクタを明示的に宣言できます。

struct my_exception : std::exception {
    virtual ~my_exception() throw() { }
    std::string message_;
};

経験則では例外仕様を作成することは決してありませんが、それが必要な場合は少なくともこの1つの一般的なケースがあります。

于 2010-07-12T23:33:05.467 に答える