Господа, я думаю многим приходится выполнять серию инициализаций COM-обьектов, при этом выполнение ветки кода надо прерывать при неуспешной инициализации хотя бы одного из них. Я встречал такие решения:
HRESULT hRes = S_OK;
hRes = COMOBJECT1.Initialize();
if ( SUCCEEDED(hRes) )
{
hRes = COMOBJECT2.Initialize();
if ( SUCCEEDED(hRes) )
{
hRes = COMOBJECT3.Initialize();
... и так далее
}
}
Некрасиво...
Попадалось и такое:
HRESULT hRes = S_OK;
hRes = COMOBJECT1.Initialize();
if ( FAILED(hRes) )
goto Err;
hRes = COMOBJECT2.Initialize();
if ( FAILED(hRes) )
goto Err;
... и так далее
}
Еще хуже
Мой вариант такой инициализации:
HRESULT hRes = S_OK;
for(; ; )
{
hRes = COMOBJECT1.Initialize();
if ( FAILED(hRes) )
break;
hRes = COMOBJECT2.Initialize();
if ( FAILED(hRes) )
break;
... и так далее
// Все ОК.break;
}
// Проверяем результат тут.if (FAILED( hRes)
{
.....
}
Как вам такой вариант? Может гуру COM посоветуют что-то еще более красивое?
Да, с исключениями правильно и красиво — если только можно их использовать.
Доводилось писать COM-объекты, которые должен были быть предельно маленькими
по размеру. Пришлось отказаться от стандартного рантайма, а вместе с ним и от
исключений. Использовал конструкцию типа
do
{
hRes = COMOBJECT1.Initialize();
if ( FAILED(hRes) )
break;
hRes = COMOBJECT2.Initialize();
if ( FAILED(hRes) )
break;
}
while(false);
, и даже потом сделал макро-обертки, т.е.
#idef USE_RUNTIME
#define com_try try
#else
#define com_try do
#endif
Т.е. код потом можно было компилить и с исключениями, и без.
Здравствуйте, disop, Вы писали:
D>Господа, я думаю многим приходится выполнять серию инициализаций COM-обьектов, при этом выполнение ветки кода надо прерывать при неуспешной инициализации хотя бы одного из них. Я встречал такие решения:
Я делал так примерно:
int iRes = 0;
i += !SUCCEDED(pObject->SomeMethod());
i += !SUCCEDED(pObject->SomeMethod1());
i += !SUCCEDED(pObject->SomeMethod2());
i += !SUCCEDED(pObject2->SomeMethod());
i += !SUCCEDED(pObject2->SomeMethod1());
i += !SUCCEDED(pObject2->SomeMethod2());
return i ? S_OK : E_FAIL;
Здравствуйте, Plutonia Experiment, Вы писали:
PE>Здравствуйте, disop, Вы писали:
D>Господа, я думаю многим приходится выполнять серию инициализаций COM-обьектов, при этом выполнение ветки кода надо прерывать при неуспешной инициализации хотя бы одного из них. Я встречал такие решения:
PE>Я делал так примерно:
PE>
Здравствуйте, Plutonia Experiment, Вы писали:
PE>Здравствуйте, Ведмедь, Вы писали:
В>Это не хорошо Потому что зачастую не имеет смысл ( или даже нельзя ) вызывать все методы, если первый сбоит.
PE>Я знаю, что нехорошо. Я же написал — лучше исключениями пользоваться. PE>Надо до конца читать
Дык если исключениями не пользуешься, все равно не стоит вызывать лишние методы
ME>struct ExceptionalHresult
ME>{
ME> ExceptionalHresult(HRESULT hr = S_OK)
ME> : hr_(hr)
ME> {
ME> if (FAILED(hr))
ME> throw std::runtime_error("Failed HRESULT has been got.");
ME> }
ME> ExceptionalHresult& operator=(HRESULT hr)
ME> {
ME> if (FAILED(hr_ = hr))
ME> throw std::runtime_error("Failed HRESULT has been got.");
ME> return *this;
ME> }
ME>};
ME>[ccode]
Да, полностью за этот способ :super: опробован временем на практике
Что-то наподобие было у Бокса в "Effective COM"
[ccode]
struct HRX {
HRX(void) { }
HRX(HRESULT hr) { if (FAILED(hr)) throw hr; }
HRX& operator=(HRESULT hr)
{ if (FAILED(hr)) throw hr; return *this; }
};
Невозможное мы сделаем сегодня — чудо займет немного больше времени. /Аноним/
EM>Так писать нельзя — AtlReportError юзает string conversion макросы, поэтому ее вызов в catch блоке чреват ...
_alloca
...
There are restrictions to explicitly calling _alloca in an exception handler (EH). EH routines that run on x86-class processors operate in their own memory frame: They perform their tasks in memory space that is not based on the current location of the stack pointer of the enclosing function. The most common implementations include Windows NT structured exception handling (SEH) and C++ catch clause expressions. Therefore, explicitly calling _alloca in any of the following scenarios results in program failure during the return to the calling EH routine:
* Windows NT SEH exception filter expression: __except (_alloca () )
* Windows NT SEH final exception handler: __finally {_alloca () }
* C++ EH catch clause expression
However, _alloca can be called directly from within an EH routine or from an application-supplied callback that gets invoked by one of the EH scenarios previously listed.
Т.е. _alloca можно безопасно вызывать не из самого обработчика, а из функции, вызываемой обработчиком.
P.S. Не понятно, что они имеют в виду говоря про "catch clause expression", но судя по всему это что-то типа:
Здравствуйте, UnrealAlex, Вы писали:
UA>Да, полностью за этот способ опробован временем на практике UA>Что-то наподобие было у Бокса в "Effective COM"
Я сам его всегда пользую, когда пишу com-обертки для своих плюсовых компонентов (тем более, что эти компоненты легко могут бросить наследника std::exception)
EM>>Так писать нельзя — AtlReportError юзает string conversion макросы, поэтому ее вызов в catch блоке чреват ...
ME>
ME>_alloca
ME>...
ME>There are restrictions to explicitly calling _alloca in an exception handler (EH). EH routines that run on x86-class processors operate in their own memory frame: They perform their tasks in memory space that is not based on the current location of the stack pointer of the enclosing function. The most common implementations include Windows NT structured exception handling (SEH) and C++ catch clause expressions. Therefore, explicitly calling _alloca in any of the following scenarios results in program failure during the return to the calling EH routine:
ME>* Windows NT SEH exception filter expression: __except (_alloca () )
ME>* Windows NT SEH final exception handler: __finally {_alloca () }
ME>* C++ EH catch clause expression
ME>However, _alloca can be called directly from within an EH routine or from an application-supplied callback that gets invoked by one of the EH scenarios previously listed.
ME>Т.е. _alloca можно безопасно вызывать не из самого обработчика, а из функции, вызываемой обработчиком.
ME>P.S. Не понятно, что они имеют в виду говоря про "catch clause expression", но судя по всему это что-то типа: ME>
The following only applies to the MS implementation of EH, I'm not
familiar with enough with any other implementation to comment.
When you throw an exception, the exception object is allocated on the
stack (please don't ask why, I can only guess.) The stack cannot be
physically unwound before entering a catch because the thrown object
might be rethrown from a catch. The stack pointer is restored after the
catch exits normally.
This means that _alloca can be called from within the catch, but the
result cannot be used outside the catch.
There is one other constraint that is really a bug. With VC6, you can't
call _alloca from within a try block. The stack pointer is not restored
correctly after taking an exception. This has been fixed in VC7.