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-expression初始化一个临时对象,称为exception object,其类型通过从 throw 操作数的静态类型中删除任何顶级cv 限定符并从“array of T”或“function”中调整类型来确定return T” 分别指向“pointer to T”或“pointer to function returned T”。临时值是一个左值,用于初始化匹配处理程序中命名的变量。如果异常对象的类型是不完整类型或指向不完整类型的指针(可能是 cv 限定的)void该程序格式不正确。除了这些限制和 15.3 中提到的类型匹配限制之外,of 的操作数throw被完全视为调用中的函数参数或 return 语句的操作数。

因为test_exception违反了三规则(或对于 C++11,五规则),在您进入块test_exception::_msg时已被删除。catch

于 2012-04-11T16:27:01.727 回答
0

由于复制了异常,因此您应该向 test_exception 对象添加一个复制构造函数。抛出的异常catch 收到的异常不同。

于 2012-04-11T16:31:43.100 回答