33

次のコードは gcc-4.7.1 ではコンパイルされませんが、clang-3.2 ではコンパイルされます。C++11 標準に準拠しているのはどれですか?

struct X {
  virtual ~X() = default;
};

struct Y : X {
  virtual ~Y() = default;
};

gcc-4.7.1 は次のように訴えています。

looser throw specifier for 'virtual Y::~Y()'
error: overriding 'virtual X::~X() noexcept(true)'

明らかに、gcc-4.7.1 は X のデフォルトのデストラクタを非スローと見なしますが、Y のデフォルトのデストラクタは非スローではありません。どうしてこれなの?誰もが標準の正しい場所を参照できますか? ありがとう。

stackoverflow で同様の質問を見ましたが、標準に関する回答は見当たりませんでした。

4

1 に答える 1

37

コンパイラは、次の理由から、ここでジレンマに陥っています。

(1)関数宣言で例外を指定throwしない (つまり、 nor noexcept(と同等) を使用しない) ということは、その関数がすべての可能な例外noexcept(true)をスローできるようにすることを意味します。

(§15.4/12、強調鉱山)例外指定のない関数、または、yieldがすべての例外を許可する形式のnoexcept(constant-expression)例外指定を持つ関数。[...]constant-expressionfalse

(2)デフォルトのデストラクタは、その暗黙の定義によって直接呼び出される関数によって許可される例外を正確に許可する必要があります。

(§15.4/14、強調鉱山) 暗黙的に宣言された特別なメンバー関数 (第 12 節) には、例外仕様が必要です。f が暗黙的に宣言されたデフォルト コンストラクター、コピー コンストラクター、ムーブ コンストラクター、デストラクタ、コピー代入演算子、またはムーブ代入演算子である場合、その暗黙的な例外仕様は、例外仕様によって T が許可されている場合にのみ、型 ID T を指定します。 f の暗黙の定義によって直接呼び出される関数。f が直接呼び出す関数がすべての例外を許可する場合、f はすべての例外を許可し、f が直接呼び出すすべての関数が例外を許可しない場合、f は例外を許可しません。

(3) 特別なメンバー (デストラクタなど) が明示的にデフォルト設定されている場合、つまり を使用する場合= default、例外の指定はオプションです(以下の「 may have」の使用を参照してください)。

(8.4.2/2、強調鉱山)明示的にデフォルト設定された関数[...]は、暗黙の宣言の例外仕様と互換性がある (15.4) 場合にのみ、明示的な例外仕様を持つことができます。[...]

標準には、明示的にデフォルト設定されたデストラクタで例外仕様を要求するステートメントはありません。

結論:したがって、明示的にデフォルト設定されたデストラクタの例外を指定しないことは、次の 2 つの方法で解釈できます。

  • すべての例外が許可されていることを意味する(上記 (1) による)
  • または、代わりに、デストラクタの暗黙のデフォルト定義で許可されているのとまったく同じ例外が許可されていることを意味します (上記の (3) に従って)。これは、あなたの場合、例外を許可しないことを意味します(上記の (2) に従って)。 .

残念ながら、GCC はこのジレンマを、基本クラス宣言の場合は 1 つの方法 (「例外なし」を優先) で解決し、派生クラスの場合は別の方法 (「すべての例外」を優先) で解決します。

この明らかにあいまいな状況の最も自然な解釈は、(2) と (3) が (1) を上書きすると仮定することだと思います。標準はそうは言っていませんが、そうすべきです。その解釈の下では、Clang はここにあるようです。

于 2012-07-16T03:27:51.303 に答える