简体   繁体   English

C ++异常的析构函数中的清理代码

[英]Clean-up code in the C++ exception's destructor

Can we use the destructor of an exception as a place to put some clean-up code? 我们可以使用异常的析构函数作为放置一些清理代码的地方吗?

In this manner we may allow the client to control the finalization step as opposed to RAII. 通过这种方式,我们可以允许客户控制完成步骤,而不是RAII。 Is this a good or a bad design? 这是好设计还是坏设计? Is this a correct solution in the context of OOP and C++? 在OOP和C ++中,这是正确的解决方案吗?

I'm currently working on an asynchronous procedure which itself starts asynchronously multiple tasks. 我目前正在开发一个异步过程,该过程本身会异步启动多个任务。 The pattern looks as follows: 该模式如下所示:

struct IAsyncResult
{
    ...
    virtual void EndCall() const;
}
typedef std::shared_ptr<IAsyncResult> IAsyncResultPtr;

struct IAsyncTask
{
    virtual IAsyncResultPtr BeginTask() = 0;
    virtual void EndTask(IAsyncResultPtr async) const = 0;
}

class CompositeTask : public IAsyncTask
{
    …
}

Unfortunately I'm unable to guarantee that each subtask's BeginTask method will not fail. 不幸的是,我无法保证每个子任务的BeginTask方法都不会失败。 So it is possible that N-1 subtasks would start successfully and the Nth fail. 因此,N-1个子任务可能会成功启动,而第N个失败。

In general it is vital to be sure that no background tasks are running before the client's code finishes. 通常,至关重要的是要确保在客户端代码完成之前没有后台任务在运行。 But sometimes the client doesn't care if some tasks fail. 但是有时客户端不关心某些任务是否失败。

So my current solution involves a custom exception which is thrown from the CompositeTask's BeginAsync method in case if one task failed to start. 因此,我当前的解决方案涉及一个自定义异常,如果一个任务无法启动,则从CompositeTask的BeginAsync方法引发该异常。 This allows a client to control the clean-up stage: 这使客户端可以控制清理阶段:

class composite_async_exception : public std::exception
{
    std::vector<IAsyncResultPtr> successfully_started_tasks;
    mutable bool manage_cleanup;
public:
    composite_async_exception(std::vector<IAsyncResultPtr> const& _successfully_started_tasks)
        : successfully_started_tasks(_successfully_started_tasks)
        , manage_cleanup(true)
    {
    }

    virtual ~composite_async_exception() throw()
    {
        if(!manage_cleanup)
            return;
        for( auto task = successfully_started_tasks.begin(); task != successfully_started_tasks.end(); ++task)
        {
            task->CancelTask();
        }
    }

    void Giveup() const throw()
    {
        manage_cleanup = false;
    }
};

And the client uses the code as shown: 客户端使用如下所示的代码:

try
{
    compositeTask.BeginAsync();
}
catch(composite_async_exception const& ex)
{
    //prevent the exception to cancel tasks
    ex.Giveup();
    // some handling
}

Are there some best practices to handle such a situation? 是否有一些最佳实践来处理这种情况?

  • The exception is eligible to be copied, the destructor would be called multiple times then. 可以复制该异常,然后将多次调用析构函数。 In your case that seem not to be a problem. 就您而言,这似乎不是问题。
  • Exception handling mechanism might stop your tasks by destroying temporary exception object aborting your tasks at throw point, not at handling one. 异常处理机制可能会通过破坏临时异常对象而使您的任务停止,而该异常对象会在抛出点而不是在处理一个异常时中止您的任务。

To verify this one should read standard, which I'm too lazy to do. 为了验证这一点,我应该读标准书,我懒得去做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM