2015-03-15 2 views
0

Возможно ли, что C++ Deleter используется со стандартными интеллектуальными указателями для определения контекста, в котором он был вызван?Вызывающий контекст Deleter

Скажем, освобождение моего ресурса может привести к ошибке.

Если мой ресурс освобождается во время разматывания стека, я, очевидно, не хочу, чтобы мой Deleter выдавал исключение в случае ошибки. Но если вызываемый Deleter был вызван с помощью функции reset(), то сообщение об ошибке для пользователя моего кода в порядке.

struct MyDeleter 
{ 
    typedef ... pointer; 

    void operator()(pointer p) 
    { 
    if (release_p_failed) 
    { 
     if (throwing_exception_is_ok) 
     throw ...; 
     else 
     hide_error_to_not_abort; 
    } 
    } 
}; 

Пример

{ 
    std::unique_ptr<..., MyDeleter> p{ ..., MyDeleter }; 

    // A: 
    p.reset(); // User intends to handle the error. Throwing exception is ok. 

    // B: Leave scope and do not throw an exception in case of an error. 
} 

ответ

1

Если вы беспокоитесь о том, чтобы выбрасывать исключение во время разматывания стека, вы должны использовать std::uncaught_exception, например.

struct MyDeleter 
{ 
    typedef ... pointer; 

    void operator()(pointer p) 
    { 
    if (release_p_failed) 
    { 
     if (!std::uncaught_exception()) // no stack unwinding in progress 
     throw ...; 
     else 
     hide_error_to_not_abort; 
    } 
    } 
}; 

Это стандартная идиома для использования, если вам когда-либо понадобится бросить любой деструктор. Конечно, это не может отличить между тем, что вызывается от std::unique_ptr::~std::unique_ptr и std::unique_ptr::reset().

Обратите внимание, что из C++ 17 std::uncaught_exception устарел и заменен на std::uncaught_exceptions, возвращая количество неперехваченных исключений, которые в настоящее время «находятся в воздухе».

+0

Это все равно позволит делетеру выбросить исключение в результате нормального разрушения. AFAICT, OP только хочет «перезагрузить», чтобы это сделать ... – defube

+0

@defube Я не уверен, что OP был после разграничения между 'std :: unique_ptr :: ~ std :: unique_ptr' и' std :: unique_ptr :: reset() ', но между разворачиванием стека и разворачиванием стека. – Walter

+0

Пример OP явно требует, чтобы '~ unique_ptr' не выбрасывал:« Оставьте поле и не генерируйте исключение в случае ошибки ». – defube

0

Нет, unique_ptr не дает какой-либо способ определения контекста вызова в Deleter.

В этом случае вам потребуется отдельная логика очистки.

0

Вы можете использовать std::uncaught_exception(), чтобы отличить нормальное разрушение от разворота штабеля.

Смежные вопросы