Здравствуйте, CEMb, Вы писали:
CEM>Ну я обычно так и делаю, но тут static
А что, статик как-то радикально меняет дело?
struct doit {};
struct AllMyRaiiStuff
{
CHandle h1, h2, h3; // каждый сам по себе умеет очищаться
AllMyRaiiStuff() {}
AllMyRaiiStuff(doit) { init(); }
void init()
{
h1 = Init1(); h2 = Init2(); h3 = Init3();
}
};
static AllMyRaiiStuff all_my_raii_stuff;
bool init_all()
{
try
{
all_my_raii_stuff = std::move( AllMyRaiiStuff(doit()) ); // выполняем init() и завершаем транзакцию
return true;
}
catch(...)
{
return false;
}
}
bool init_all_another_way()
{
try
{
all_my_stuff.init(); // выполняем init() не атомарно...
return true;
}
catch(...)
{
all_my_stuff = std::move( AllMyRaiiStuff() ); // одним махом откатываем
return false;
}
}
Только если лень переписывать код, нацарапанный карандашом на столешнице.
Здравствуйте, watchmaker, Вы писали:
CEM>>я делаю инициализацию объекта в конструкторе. Но для статика явного конструктора нет.
W>Ну-ка, распиши всё же подробнее чем тебе static мешает использовать RAII? Никому ведь не мешает, а тебе мешает. Чем же твой код такой особенный?
W>Нет конструктора — ну так напиши его. Собственно как делается во всех случаях.
я не пойму как, можно пример?
Здравствуйте, CEMb, Вы писали:
CEM>Почитал соседнюю ветку, и вспомнилось...
CEM>Принцип создания функции инициализации:
| Скрытый текст |
| CEM>CEM>BOOL CApp::InitCommon()
CEM>{
CEM> try
CEM> {
CEM> if(!m_zero.InitCommon())
CEM> throw 0;
CEM> if(!m_one.InitCommon())
CEM> throw 1;
CEM> if(!m_two.InitCommon())
CEM> throw 2;
CEM> //...
CEM> }
CEM> catch(int iExc)
CEM> {
CEM> switch(iExc)
CEM> {
CEM> //...
CEM> case 3:
CEM> m_two.UninitCommon();
CEM> case 2:
CEM> m_one.UninitCommon();
CEM> case 1:
CEM> m_zero.UninitCommon();
CEM> }
CEM> return FALSE;
CEM> }
CEM> return TRUE;
CEM>}
CEM>
CEM>у меня конкретно в коде были вызовы статических методов классов для инициализации общих данных, (через C:: ). |
| |
CEM>чтоб понятнее, в чём суть, лучше так:
| Скрытый текст |
| CEM>CEM>BOOL CApp::Init()
CEM>{
CEM> try
CEM> {
CEM> m_hSome0 = InitSome0()
CEM> if (!m_hSome0)
CEM> throw 0;
CEM> m_hSome1 = InitSome1()
CEM> if (!m_hSome1)
CEM> throw 1;
CEM> m_hSome2 = InitSome2()
CEM> if (!m_hSome2)
CEM> throw 2;
CEM> //...
CEM> }
CEM> catch(int iExc)
CEM> {
CEM> switch(iExc)
CEM> {
CEM> //...
CEM> case 3:
CEM> Release(hSome2);
CEM> case 2:
CEM> Release(hSome1);
CEM> case 1:
CEM> Release(hSome0);
CEM> }
CEM> return FALSE;
CEM> }
CEM> return TRUE;
CEM>}
CEM>
|
| |
CEM>Часто в примерах встречал код, который инициализировал некоторые члены класса один за другим, в случае ошибки делал деинициализацию уже готовых. В результате к хвосту функции число вызова деинициализаторов было велико. Ну и повторы кода на каждом условии.
CEM>Как вариант, люди использовали некую булеву переменную для понимания, что инициализации идут хорошо, каждая новая инициализация обкладывалась условием на эту переменную. В конце эта переменная проверялась, если false, то проверялись опять же все хендлы на валидность, и делалась деинициализация.
CEM>Мне кажется, мой код проще и нагляднее, быстро расширяется, можно не бояться забыть, что что-то пропустил.
CEM>Жду: критику, доработку, идеи
Сделать uninit / release — который ничего не делает, если ресурс не был выделен.
Если тебе так хочется JavaStyle — то пусть эксепшн кидают InitCommon / InitSome0 — а в catch вызываеться — UninitCommon() -> который вызовет m_two.UninitCommon() и т.п.
BOOL CApp::InitCommon()
{
try
{
m_zero.InitCommon();
m_one.InitCommon();
m_two.InitCommon();
}
catch(ExpectedException ee)
{
LogError(ee);
UninitCommon();
return FALSE;
}
return TRUE;
}
void CApp::UninitCommon()
{
m_two.UninitCommon();
m_one.UninitCommon();
m_zero.UninitCommon();
}
Или вообще в место BOOL — кидать исключения ->
void CApp::InitCommon()
{
try
{
m_zero.InitCommon();
m_one.InitCommon();
m_two.InitCommon();
}
catch(ExpectedException ee)
{
LogError(ee);
UninitCommon();
throw ExpectedException(ee);
}
}
void CApp::UninitCommon()
{
m_two.UninitCommon();
m_one.UninitCommon();
m_zero.UninitCommon();
}