2010-01-23 27 views
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)是否对其进行了优化?还是我错过了某些内容?

+0

可能是编译器最初看到复制构造函数是微不足道的,并决定使用它。当你添加一个用户定义的拷贝构造函数时,它可能意识到将呼叫作为一个优化去掉可能会更好。无论如何,即使编译器优化了副本,也必须遵循三法则。 – UncleBens

+0

对我来说没有崩溃,实际上在代码中没有错误。您的编译器必须处理异常对象的生命,您的代码是按规则操作的。 !!!!!!!!!!所以开关编译器!!!!!!!!!! – erick2red

回答

4

具体地说, 抛出magicException对象的析构函数被捕捉块之前调用 。

是的,正如您在标准中的引用所述,复制是由编译器进行的,并且原始(可能)被丢弃。你的问题是你原来的代码中缺少一个拷贝构造函数。但是,允许C++编译器在各种情况下(包括本文)移除(或添加)复制构造函数调用。

+0

我已经添加了一个副本构造函数(请参阅我的文章),但它没有被调用。我的问题是,为什么没有调用复制构造函数。 –

+0

查看我的编辑 - 编译构造函数调用可能会被编译器忽略,即使它们有副作用。 – 2010-01-23 09:59:46

+0

谢谢,我发现一篇文章澄清了这一点:http://en.wikipedia.org/wiki/Return_value_optimization#Other_forms_of_copy_elision –