Код очистки в деструкторе исключения C ++ - PullRequest
2 голосов
/ 21 февраля 2012

Можем ли мы использовать деструктор исключения в качестве места для размещения кода очистки?

Таким образом, мы можем позволить клиенту контролировать этап завершения в отличие от RAII. Это хороший или плохой дизайн? Это правильное решение в контексте ООП и C ++?

В настоящее время я работаю над асинхронной процедурой, которая сама запускает асинхронно несколько задач. Шаблон выглядит следующим образом:

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
{
    …
}

К сожалению, я не могу гарантировать, что метод BeginTask каждой подзадачи не завершится с ошибкой. Таким образом, возможно, что подзадачи N-1 начнутся успешно, а N-й сбой.

В общем, важно убедиться, что никакие фоновые задачи не выполняются до завершения кода клиента. Но иногда клиенту все равно, что некоторые задачи не выполняются.

Таким образом, мое текущее решение включает в себя пользовательское исключение, которое выдается из метода BeginAsync CompositeTask в случае, если не удалось запустить одну задачу. Это позволяет клиенту контролировать этап очистки:

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;
    }
};

И клиент использует код, как показано:

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

Существуют ли передовые практики для разрешения такой ситуации?

1 Ответ

1 голос
/ 22 февраля 2012
  • Исключение может быть скопировано, деструктор будет вызываться несколько раз. В вашем случае это не проблема.
  • Механизм обработки исключений может остановить ваши задачи, уничтожив объект временного исключения, прерывающий ваши задачи в точке выброса, а не при обработке.

Чтобы убедиться в этом, нужно прочитать стандарт, что мне лень делать.

...