我有一个类将用户给出的工作分配给多个线程.像(简化)的东西:
class MT {
public:
MT();
void work1(/*args*/);
void work2(/*args*/);
void work3(/*args*/);
//waits until all threads complete, returns whether the work has been completed
//successfully, throws any exceptions that have been raised in the threads.
bool is_ok();
~MT();
private:
// thread pool
}
Run Code Online (Sandbox Code Playgroud)
用户使用该类如下:
void foo()
{
MT mt;
mt.work1(/*userdata*/);
mt.work2(/*userdata*/);
mt.work1(/*userdata*/);
status = mt.is_ok();
if (status) {
mt.work3(/*userdata*/);
//...
}
//...
}
Run Code Online (Sandbox Code Playgroud)
该类永远不会成为某个对象的一部分,始终存储在堆栈中.
我想以某种方式发出在其他线程中工作时引发的任何异常.不幸的是,我知道线程是否在加入后才成功完成.因此,我必须在以下两种选择之间做出选择:
加入析构函数中的线程MT并抛出在工作时产生的异常(如果有的话).如果抛出了多个异常,请从最早的任务中选择一个异常.如果调用析构函数进行堆栈展开(我们可以使用std::uncaught_exception,检查这个,吞下任何异常以防止terminate().
指示用户始终is_ok在析构函数之前调用.
我认为第一个选项更干净,因为用户不需要调用任何东西.但是,通常非常强烈地不鼓励从析构函数中抛出.提出的论点是:
terminate().不知怎的,我倾向于认为上述论点不适用于此:
foo意味着工作失败.投掷或不投掷析构函数并不是行为的重大改变.不,不要从析构函数中抛出.打电话is_ok,接听和忽略.与close()流相同.
如果用户is_ok 想要确定工作已经完成,则可以调用,并且在失败时会抛出异常.
在实践中,这很少是不方便的.如果用户编写具有多个返回点的函数,但是(不幸的是)这是他们必须处理的问题,因为C++不提供为您执行此操作的方法.如果你认为这是反社会的,那么,看看如果你std::thread在没有加入或分离它的情况下销毁C++ 11中会发生什么.你打败了:-)
因此,用户调用is_ok所有非错误退出路径.当已经存在异常时,用户不会打扰它,因为无论如何它们都无法处理另一个异常.同样,这与close()流相同:如果您希望通过编写缓冲流来查看错误,那么您只需要显式关闭或刷新.
即使解决了上述问题,根据堆叠是否被解开而投掷或不投掷是行为的重大改变,应该不鼓励.
至少在C++ 03中,它也不可能正确完成.Herb Sutter解释说,我不知道C++ 11在这方面是否有任何改变,但std::uncaught_exception 并没有告诉你需要知道什么.
从您的链接到cppreference.com:
std :: uncaught_exception()== true时抛出的任何异常都会调用std :: terminate.
我很确定这是错误的.terminate如果异常转义为作为堆栈展开的一部分调用的析构函数,则调用它,但不会因为析构函数在展开期间抛出并捕获异常而调用它.
如果来电者认为他们可以做一些有用的事情,在析构函数抛出一个异常,那么他们可以编写调用一个辅助类is_ok中的析构函数,并把那在你的对象.如果你认为你的类可以使用相同的异常做一些有用的事情,那么除了在析构函数中忽略它之外你可以做一些事情,但你仍然不应该让它离开析构函数.
| 归档时间: |
|
| 查看次数: |
322 次 |
| 最近记录: |