1

スローした例外クラスの (少なくとも私にとっては) 非常に奇妙な動作に遭遇しました。私がしていることnewは、例外クラスのコンストラクターで文字列を介してメモリを割り当て、文字で埋めることです。これまでのところ、すべて問題ありません。コードをデバッグすると、ポインターが実際に正しいコンテンツを持っていることを Visual Studio で確認できます。

今、奇妙なことが起こります。私の次のブレークポイントは、構築後に例外が渡される catch ブロックにあります。ここでは、例外オブジェクトに含まれる文字列の内容がひどく破損していることをデバッガーで確認できます。住所は全く変わっていないのに!そのため、文字列の内容が破壊されるようです。

したがって、例外デストラクタにブレークポイントを設定すると、実際には、catch ブロックに入る前に呼び出されます。catch ブロックへの参照によって例外を渡すことを学んだので、これは私を大いに混乱させます。しかし、動的に作成されたデータにアクセスする前にデストラクタが呼び出された場合...

私がいる状況を示す最小限の例を作成しました。

#include <iostream>
#include <cstring>

class test_exception {
public:
    test_exception();
    ~test_exception() {
        delete[] _msg;
    }

    // Getter Functions
    char* errorMessage() const {
        return _msg; 
    }
private:
    char* _msg;
};

test_exception::test_exception()
{
    _msg = new char[22];
    strcpy(_msg, "This is a test string");
}

int main(int argc, char* argv[])
{
    try {
        throw test_exception();
    } catch (const test_exception& err) {
        std::cout << err.errorMessage() << std::endl;
    }

    std::cin.get();

    return 0;
}

それが奇妙な MS の動作なのか、それとも try - catch - ブロックの使用方法を誤解していたのかを誰かが教えてくれれば、それは素晴らしいことです。

4

2 に答える 2

3

例外は、スローされるときにコピーされます (C++ 11 では、場合によっては移動されます)。C++11 の引用、§15.1/3:

throw 式は、例外オブジェクトと呼ばれる一時オブジェクトを初期化します。その型は、throw のオペランドの静的型から最上位のcv 修飾子Tを削除し、「配列」または「関数」から型を調整することによって決定されます。 return T」を「pointer to T」または「pointer to function return T」にそれぞれ変更します。一時的なものは左辺値であり、一致するhandlerで指定された変数を初期化するために使用されます。例外オブジェクトの型が不完全型または (おそらく cv 修飾された) 以外の不完全型へのポインターである場合voidプログラムの形式が正しくありません。これらの制限と 15.3 で説明されている型の一致に関する制限を除いて、 のオペランドはthrow、呼び出しの関数引数または return ステートメントのオペランドとして正確に扱われます。

は 3の規則(または C++11 の場合は5 の規則)test_exceptionに違反しているため、ブロックに入る時点で既に削除されています。test_exception::_msgcatch

于 2012-04-11T16:27:01.727 に答える
0

例外はコピーされるため、コピー コンストラクターを test_exception オブジェクトに追加する必要があります。スローされた例外は、キャッチによって受信されたものと同じではありません。

于 2012-04-11T16:31:43.100 に答える