14

アンドレイ・アレキサンドレスクのエラー処理に関する講演中:

C ++およびBeyond2012:Andrei Alexandrescu-C ++での体系的なエラー処理(約30分)を参照してください。

Andreiは、次のコードを提示します。

~Expected()
{
    using std::exception_ptr;
    if (gotHam) ham.~T();
    else spam.~exception_ptr();
}

このデストラクタは、unionあるタイプTまたはのいずれかを含むをクリーンアップしていますstd::exception_ptr。ユニオンは、を使用して設定されplacement newます。

次にAndreiはusing std::exception_ptr;、次のコードは解析しないため、が必要であると説明します。

    else spam.~std::exception_ptr();

つまり、別の名前空間にあるクラスのデストラクタを明示的に呼び出す必要がある場合は、usingディレクティブが常に必要です。

2番目の例が解析されないのはなぜですか?

次のコードは有効な代替手段ですか?

    else delete spam;

これは、のデストラクタを明示的に呼び出すのと同じ効果がありますか?std::exception_ptr

4

3 に答える 3

10

Andreiはusing std::exception_ptr;、コンパイラが壊れているために使用している可能性があります。

必要がない。spam.~exception_ptr();それがなくても問題なくコンパイルできるはずです。

3.4.5/3。unqualified-idが〜type-nameの場合、type-nameはpostfix-expression全体のコンテキストで検索されます。オブジェクト式のタイプTがクラスタイプCの場合、タイプ名もクラスCのスコープで検索されます。

それは確かにgccでコンパイルされます。

何らかの理由でqualified-nameを使用する必要がある場合は、spam.std::exception_ptr::~exception_ptr();コンパイルも行います。

于 2013-01-04T12:50:45.730 に答える
8

ここでの問題は、~std::exception_ptr()実際には呼び出そうとしている関数の名前ではなく、単に~exception_ptr()。そして、それは別の名前空間のクラスに属しているので、アクセスできません(編集:nmが彼の答えで指摘しているように、C ++11標準の§3.4.5/3に従ってアクセスできるはずですが、Microsoftコンパイラはこのように動作します)。

クラスを名前空間に取り込む代わりの方法があります。修飾されたクラス名を使用して明示的な呼び出しを行います。

else spam.std::exception_ptr::~exception_ptr(); // This is legal

2番目の質問については、R。Martinho Fernandesがコメントで正しく説明しているように、delete演算子を呼び出すことは、デストラクタを呼び出すことと同じではありません。厄介な名前の関数も呼び出しますoperator delete()

于 2013-01-04T12:27:03.833 に答える
3

文法がid式を要求し、Gorpikが指摘spam.~std::exception_ptrしたように、id式ではないため、構文は許可されていません。しかし、修飾が必要な理由がわかりません。構文を説明する句で、次のことを思い出してください。~std::exception_ptrspam.std::exception_ptr::~exception_ptr()

クラスの名前はそのクラススコープに挿入されるため(第9節)、クラスの名前もそのクラスのネストされたメンバーと見なされます。

spam.~exception_ptr()ですから、using句がなくても有効なはずだと思います。ところで

namespace ns {
struct Foo {};
}

void f()
{
    ns::Foo x;
    x.~Foo();
}

私がアクセスしたすべてのg++(非常に古い2.95を含む)でクリーンにコンパイルします。これは、C ++ 11の更新された共用体タイプのコンテキストで機能しない場合、実装のバグであるという私の意見を確認しているようです。

g ++ 4.7.1で編集すると、以下も-std = c++11でコンパイルされます。

namespace ns {
struct Foo {};
}

struct Bar {};

union U {
    ns::Foo f;
    Bar b;
};

struct C {
    bool b;
    U u;
    ~C() {
        if (b)
            u.f.~Foo();
        else
            u.b.~Bar();
    }                
};

void f()
{
    C c;
}

そのため、Andreiは、解決する必要のない問題を試みて(彼が使用していたコンパイラのバグによって、またはクラス名がクラスのスコープにインポートされるという事実を忘れることによって)脇道に追いやられました。

于 2013-01-04T12:36:47.210 に答える