- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个关于异常生命周期的可移植性问题。在下面的代码中,异常在一个线程 (mySlave) 中抛出并使用 std::exception_ptr
转移到另一个线程 (myMaster) . myMaster 总是通过 std::condition_variable
等待不同的事件. mySlave 中的一个异常(exception)就是这样的事件。在myMaster中等待的谓词函数中,我检查异常指针是否为空。如果在mySlave中抛出异常,我将异常指针复制到myMaster中的一个临时变量中,将原来的异常指针设置为null并在myMaster中重新抛出。这样,一旦程序从异常中恢复,原始异常指针就可以在谓词函数中使用。
这在 VC14 上运行良好,但最终的软件很可能在未来移植到其他平台。在我的代码中,所有 exception_ptr
重新抛出后对异常的引用将超出范围,因此原始异常将被销毁。我担心的是 std::rethrow_exception
保证在重新抛出异常时总是生成异常的拷贝,或者如果它也可以使用对异常的引用,导致它在我 try catch 时不再有效 if in myMaster?
#include <mutex>
#include <thread>
#include <atomic>
#include <exception>
#include <iostream>
#include <memory>
class SomeClass
{
public:
/*...*/
void MaseterFunction();
void SlaveFunction();
private:
/*...*/
std::mutex mutex_gotEvent;
std::condition_variable condVar_gotEvent;
std::exception_ptr slaveLoopException;
/*...*/
std::atomic<bool> running = true;
};
class MyException : public std::runtime_error
{
public:
MyException() : std::runtime_error("Ooops") {}
};
void SomeClass::SlaveFunction()
{
try
{
throw MyException();
}catch(const std::exception& e)
{
std::unique_lock<std::mutex> lock(mutex_gotEvent);
slaveLoopException = std::current_exception();
condVar_gotEvent.notify_all();
}
}
void SomeClass::MaseterFunction()
{
while (running)
{
try
{
{
/*Wait for something interesting to happen*/
std::unique_lock<std::mutex> lock(mutex_gotEvent);
condVar_gotEvent.wait(lock, [=]()->bool {
return !(slaveLoopException == nullptr); // Real code waits for several events
});
}
/*Care for events*/
/*...*/
if (slaveLoopException)
{
std::exception_ptr temp_ptr = slaveLoopException;
slaveLoopException = nullptr;
std::rethrow_exception(temp_ptr);
}
}
catch (const MyException& e)
{
std::cout << e.what();
running = false;
}
}
}
int main()
{
std::shared_ptr<SomeClass> someClass = std::make_shared<SomeClass>();
std::thread myMaster([someClass]() {someClass->MaseterFunction(); });
std::thread mySlave([someClass]() {someClass->SlaveFunction(); });
std::cin.ignore();
if (myMaster.joinable())
{
myMaster.join();
}
if (mySlave.joinable())
{
mySlave.join();
}
return 0;
}
我考虑过声明 temp_ptr
在类(class)或使用 std::atomic<bool>
除了要在谓词函数中使用的异常指针之外的变量。但是,这两种解决方案都会在不再使用异常后使异常保持事件状态,这对我来说似乎不是很优雅。也可以在 myMaster 的每个 catch block 中将异常指针设置为 null,但我认为这可能会在稍后添加新异常时引入错误,而程序员忘记将异常指针设为 null。
编辑:
我发现了关于这个主题的以下陈述:
The exception object referenced by an std::exception_ptr remains valid as long as there remains at least one std::exception_ptr that is referencing it
The VS implementation of rethrow_exception appears to make a copy of the exception. Clang and gcc do not make copies.
The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (§18.8.5) that refers to the exception object is destroyed, whichever is later.
从 (1) 我希望过早销毁异常。从 (2) 开始,我希望在使用 VC 作为拷贝时这不会有任何效果。从 3 开始,我不知道这是否可以在使用 gcc 或 clang 时拯救我。我的意思是,退出是通过重新抛出发生的,但它不是从处理程序中重新抛出的。当临时指针被销毁时,新的处理程序是否已经被认为是事件的,或者指针是否首先被销毁并随之产生异常,从而使后续的 catch block 留下无效的异常引用?
最佳答案
CppRef 指出 rethrow_exception
-- 抛出先前捕获的异常对象。我自己没有检查标准(但见下文),但是:
在我看来,从你重新抛出异常的那一刻起,异常处理“恢复正常”,即实现的工作是保留抛出的对象,语言不关心你是否通过正常的 throw
throw 或通过 rethrow_exception
.
换句话说:exception_ptr 需要在 rethrow_exception
点有效,在此之后,抛出的异常与任何其他异常相同,无论它是否与原始异常指针共享都无关紧要。
OP提供了很好的link用标准报价:
4/ The memory for the exception object is allocated in an unspecified way, except as noted in §3.7.4.1. If a handler exits by rethrowing, control is passed to another handler for the same exception. The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type
std::exception_ptr
(§18.8.5) that refers to the exception object is destroyed, whichever is later. In the former case, the destruction occurs when the handler exits, immediately after the destruction of the object declared in the exception-declaration in the handler, if any. In the latter case, the destruction occurs before the destructor ofstd::exception_ptr
returns. The implementation may then deallocate the memory for the exception object; any such deallocation is done in an unspecified way. [ Note: a thrown exception does not propagate to other threads unless caught, stored, and rethrown using appropriate library functions; see §18.8.5 and §30.6. —end note ]
这似乎暗示了我上面写的:异常对象只要需要就可以存在:
whichever is later
部分引用似乎明确指出了这一点。
更新:我错过了 OP 不会从处理程序中重新抛出,所以我也不确定这里应该发生什么。
我确实相信在rethrow_exception
之后飞行中的(新)异常应该被视为好像它是由正常的 throw
生成的一样表达式 - 其他任何内容都没有意义。
我在这里推测的方式是甚至在 std::exception_ptr
之前每个实现都有一个类似于 std::exception_ptr
的内部机制因为它必须使抛出的异常对象(复制或不复制)在正常堆栈帧外部保持事件状态,直到堆栈上的任何处理程序不再需要它为止。所以我可以推测 clang 或 gcc 不会进行复制,而是在您调用 throw/rethrow_exception 时立即保存一个“内部 exception_ptr”。
关于c++ - 在调用 std::rethrow_exception 可移植后,是否销毁指向异常的最后一个 std::exception_ptr?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43799790/
当你有一个对象 OBJ1 包含一个关键部分 CS 和一个指向另一个对象 OBJ2 的指针时,我无法弄清楚什么是正确的关闭过程 假设您有两个函数 A 和 B。 A进入临界区,修改OBJ2中的数据后离开临
我有一个成员变量声明为 CComPtr m_spXMLDoc; XML 文档是这样创建的 CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC
在我的工作平台中,我遇到了 session_destroy 问题 function logout() { $_SESSION['id'] = ''; session_destroy(); } 在这
如何使用 destroy 删除 jScrollPane。请您给出以下代码的简单示例: $(document).ready(function() { $(".div1").jScrollPane
这是我在这里发表的第一篇文章,但我想对社区表示感谢,因为通过来到这里并在已经得到解答的问题中找到解决方案,我已经无数次找到了问题的解决方案。 话虽这么说,我想进入正题。我正在 Code Gear 的
我在导航 View 中工作。在此导航 View 中,您可以偶然发现个人资料页面。在此个人资料页面中,您可以看到与当前个人资料相关的其他个人资料(基本上是数据 View 中显示的图片)。您可以通过点击这
我想销毁项目中的 session ,这样当我单击“注销”时,它会转到页面“KillSession.jsp”,在该文件中我编写了“session.invalidate();”然后我将用户重定向到登录页面
我有关于 Thread 的 2 问题,我只是想澄清一些事情。使用以下代码: public class MyThread implements Runnable { Boolean StopTh
我遇到了内存泄漏,代码类似于下面的代码(这是每个循环都有不同输入的模拟)。 问题 对象 Object_XXX 非常复杂,它与数据库以及其他填充了数据库数据的对象有连接。 for(int i=0
当我在 Python 中启动一个类时,我给它一些值。然后我调用类中执行某些操作的方法。这是一个片段: class TestClass(): def __init__(self):
我想删除所有 div、类、属性和几乎所有 CKEDITOR 添加到 DOM 的内容。例如调用 jquery tabs("destroy");将删除所有由 jQuery 选项卡添加的 div。我怎样才能
我想清除析构函数中的一个映射,但我不知道它是否为空。如果我按如下方式清除它可以吗? for(std::map::iterator it = m_map.begin(); it != m_map.end
我正在尝试克隆 TikTok 应用。对于主屏幕,我制作了一个 VerticalViewPager(自定义 View 分页器),其中包含“点赞”按钮、标题和评论。我正在从 Firebase 检索视频。
我正在制作自己的游戏。目标之一是在世界中拥有尽可能多的物体。在这个游戏中,需要在一些不可预测的时间段内创建许多对象(比如武器开火会创建一个对象),一旦该弹丸击中某物,该对象也需要被摧毁(也许它击中的东
有没有办法在 JavaScript 中破坏 HTML5 WebWorker? 这是我的情况:我有一个 Web 应用程序生成相当数量的 WebWorker(在 16 到 32 之间的任何地方)来优化一些
如何销毁 php 中的 session ? 事情是当用户点击注销按钮时, session 将结束,他将被重定向到 index.php 这是我的代码 客户.php 这是来自用户想要再次登录的 ind
关于 GtkBuilder 的问题。 当我们取消引用构建器指针时,它是否会破坏构建器创建的所有屏幕/小部件? if( builder_ptr ) g_object_unref(G_OBJECT
有没有办法销毁 WebView 实例?如果页面加载,并说视频开始播放,我希望能够,当我隐藏 WebView 时,基本上可以销毁它,或者至少重置它。 我知道我可以听 visibleProperty 并执
我有一组可拖动的元素。如何删除可拖动功能? $('.draggable').draggable('disable') 在我的情况下不是一个选项 $('.draggable').draggable('d
下面的代码会抛出一个 EZDecompressionError 消息 'Invalid ZStream operation' 每当行 Reader.Free 被执行。有人可以告诉我这段代码有什么问题吗
我是一名优秀的程序员,十分优秀!