引用捕获的抛出对象的生命周期

时间:2010-01-23 09:47:02

标签: c++ exception-handling throw lifetime

C ++标准,第15.1.4段sais:

  

抛出异常的临时副本的内存以未指定的方式分配,除非在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并关闭了优化),或者我错过了什么?

1 个答案:

答案 0 :(得分:4)

  具体来说,是析构函数   抛出magicException对象获取   在捕获块之前调用。

是的,正如您从标准中引用的那样,编译器会复制一份副本,并且原始(可能)被丢弃。您的问题是原始代码中缺少复制构造函数。但是,允许C ++编译器在各种情况下删除(或添加)复制构造函数调用,包括这种情况。