3

C ++標準、パラグラフ15.1.4は次のように述べています。

スローされる例外の一時コピー用のメモリは、3.7.3.1に記載されている場合を除き、不特定の方法で割り当てられます。その例外に対して実行されているハンドラーがある限り、一時は存続します。

なぜこのコードがクラッシュするのか疑問に思っています(ベストプラクティスではないことはわかっています):

class magicException
{
private:
    char* m_message;

public:
    magicException(const char* message)
    {
        m_message = new char[strlen(message) + 1];
        strcpy(m_message, message);
    }

    ~magicException()
    {
        cout << "Destructor called." << endl;
        delete[] m_message;
    }

    char* getMessage()
    {
        return m_message;
    }
};

void someFunction()
{
    throw magicException("Bang!");
}

int main(int argc, char * argv[])
{
    try
    {
        someFunction();
    }
    catch (magicException& ex)
    {
        cout << ex.getMessage() << endl;
    }

    return 0;
}

具体的には、スローされたmagicExceptionオブジェクトのデストラクタがcatchブロックの前に呼び出されます。ただし、コピーコンストラクターをクラスに追加すると、次のようになります。

magicException(const magicException& other)
{
    cout << "Copy constructor called." << endl;
    m_message = new char[strlen(other.m_message) + 1];
    strcpy(m_message, other.m_message);
}

次に、コードが機能し、デストラクタが予期された場所(catchブロックの終わり)で呼び出されますが、興味深いことに、コピーコンストラクタはまだ呼び出されません。コンパイラー(最適化がオフになっているVisual C ++ 2008)によって最適化されていますか、それとも何かが足りませんか?

4

1 に答える 1

4

具体的には、スローされた magicException オブジェクトのデストラクタが catch ブロックの前に呼び出されます。

はい、標準からの引用が言うように、コピーはコンパイラによって取得され、元の (おそらく) 破棄されます。問題は、元のコードにコピー コンストラクターがないことです。ただし、C++ コンパイラは、このような状況を含め、あらゆる種類の状況でコピー コンストラクター呼び出しを削除 (または追加) することができます。

于 2010-01-23T09:56:35.483 に答える