C++:抛出异常时堆栈不会展开
你好,
我在我的一个 C++ 项目中遇到了一个很奇怪的问题: 我编写了一个 C++ 套接字包装器,它尝试连接到给定的主机和端口(通过 IPv4/TCP),并在发生错误(例如“连接被拒绝”)时抛出 SocketException(从 std::runtime_error 派生)。异常被正确捕获,错误消息按预期写入控制台,但显然我的 Socket 类的析构函数没有被调用(它也应该向 std::cerr 输出一条消息,但该消息仅在连接有效且如果套接字超出堆栈,例如在尝试使用套接字的函数结束时,套接字将被销毁。析构函数应该关闭封装的套接字,但在抛出异常时,套接字保持打开状态(您可以使用 lsof 将其视为未知类型的套接字),因此析构函数中似乎根本没有执行任何代码)。 由于我无法用简单的测试用例重现这个问题,我的猜测是它在某种程度上与我的项目相当复杂的结构有关:我有一个核心应用程序,其中包含 Socket 类的代码并提供一个 Singleton 类,该类提供实现用于通信的协议并返回请求结果的方法,对这些方法之一的每次调用都会生成自己的 Socket 实例,并为其提供有关要使用的主机和端口的必要信息。为了简化套接字生成和管理,使用了 std::auto_ptr ,如果方法完成并且堆栈被清理,它应该删除套接字,根据控制台输出它可以正常工作,但它应该在抛出异常时以相同的方式工作,至少到目前为止我是这么认为的。 核心能够通过 dlopen 以共享对象格式加载插件,并通过共享对象中的 extern C 声明函数获取指向插件类实例的指针。 该实例现在使用核心提供的单例与服务器通信并显示检索到的数据。
我的问题是:使用共享对象时堆栈展开是否有限制,或者我应该在哪里寻找我错过的东西以使其正常工作?
Hallo,
I have a quite strange problem in one of my C++ projects:
I wrote a C++ Socket wrapper, that tries to connect to a given host and port (via IPv4/TCP) and throws a SocketException (derived from std::runtime_error), if an error occurs (e.g. 'Connection refused'). The exception is caught properly and an error message is written to console as expected, but apparently the destructor of my Socket class is not called (it should output a message to std::cerr, too, but the message only appears if connection works and Socket is destroyed later on if it goes out of stack, e.g. on end of the function that tries to utilize the socket). The destructor should close the encapsulated socket, but on exception thrown the socket remains open (you can see it with lsof as socket of unknown type), so no code in the destructor seems to be executed at all).
As I couldn't reproduce this problem with a simple testcase, my guess is that it somehow has to do with the quite complex structure of my project: I have a core application containing the code for the Socket class and providing a Singleton class which offers methods that implement the protocol used for communication and return the results of a request, each call to one of these methods generates its own instance of a Socket and provides it with the necessary information about host and port to use. To simplify socket generation and managment, a std::auto_ptr is used, which should delete the Socket if method has finished and stack is cleaned up, which works properly according to console output, but it should work the same way on an exception thrown, at least that is what was my opinion until now.
The core is able to load plugins in shared object format by dlopen and gets a pointer to the plugin's class instance via an extern C declared function in the shared object.
This instance now uses the Singleton provided by the core to communicate with the server and show retrieved data.
My question is: are there limitations to stack unwinding when using shared objects, or where should I look for the thing I missed out to make this work properly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果从构造函数抛出异常,则不会调用析构函数。
If your exception is thrown from the constructor, the destructor will not be called.
好吧,忘了那个吧。再次查看代码表明,构造函数中可能已引发异常,因此析构函数不会被调用,正如 C++ 标准中所描述的那样。不扔进构造函数解决了问题。这就是 Java 编程对 C++ 技能的影响 ^^
请原谅噪音。
Ok, forget that one. Another look in the code showed that there was the possibility that an exception could have been thrown already in constructor so that the destructor would not have been called, as it's described in C++ standard. Not throwing in the constructor solved the problem. That's what programming in Java is doing to your C++ skills ^^
Excuse the noise, please.
如果您在 Linux 上编程,则可能会触发一个问题,即无法正确捕获从共享库抛出的异常(异常类型确定问题)。这个问题在此处和此处,我相信您可以在谷歌上搜索更多解释相同问题的页面。
如果这是一个问题,我仍在寻找解决方案:(
If you are programming on linux, you might be triggering a problem where the exception thrown from a shared library is not caught properly (problem with exception type determining). This problem is explained here and here, and I am sure you could google up more pages explaining the same problem.
If that is a problem, I am still looking for a solution :(