通过引用捕获的抛出对象的生命周期
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 关闭了优化),还是我遗漏了一些东西?
The C++ Standard, paragraph 15.1.4 sais:
The memory for the temporary copy of the exception being thrown is allocated in an unspecified way, except as noted in 3.7.3.1. The temporary persists as long as there is a handler being executed for that exception.
I'm wondering why this code crashes (I know that it's not best practice):
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;
}
Specifically, the destructor of the thrown magicException object gets called before the catch block. If I however add a copy constructor to my class:
magicException(const magicException& other)
{
cout << "Copy constructor called." << endl;
m_message = new char[strlen(other.m_message) + 1];
strcpy(m_message, other.m_message);
}
Then the code works, the destructor gets called at the expected place (the end of the catch block), but interestingly the copy constructor still doesn't get called. Is it optimized away by the compiler (Visual C++ 2008 with optimizations turned off), or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,正如您对标准的引用所说,编译器会获取副本,而原始文件(可能)会被丢弃。您的问题是原始代码中缺少复制构造函数。然而,C++ 编译器可以在各种情况下删除(或添加)复制构造函数调用,包括这种情况。
Yes, as your quote from the standard says, a copy is taken by the compiler, and the original (probably) discarded. Your problem is the lack of a copy constructor in your original code. However, a C++ compiler is allowed to remove (or add) copy constructor calls in all sorts of situations, including this one.