Форум: "Прочее";
Текущий архив: 2014.03.16;
Скачать: [xml.tar.bz2];
ВнизC++ и обработка исключений, или за секунду до холивара Найти похожие ветки
← →
ProgRAMmer Dimonych © (2013-09-25 20:31) [0]Окончательно запутался в том, что мне говорят MSDN и гугл на тему обработки исключений.
Что я хочу
Хочу аналог Delphiйского (псевдокодом):pData = MemAlloc(...);
try
// Много кода
Result := pData;
except
MemFree(pData);
raise;
end;
Что я могуpData = MemAlloc(...);
__try
{
// Много кода
return pData;
}
__except(MemFree(pData), EXCEPTION_CONTINUE_SEARCH) { return NULL; }
Что мне не нравится
Не нравится необходимость писатьreturn NULL
, чтобы не лезло предупреждений компилятора.
Стандартный catch с throw внутри не подходит, т.к. его нельзя использовать в одной процедуре с __finally (а __finally там нужен и уже есть). Внутри нестандартного __except делать throw, судя по всему, нельзя, т.к. throw не умеет работать с системными (не C++) исключениями.
Вопрос
Как гениальный Страуструп и его последователи, молящиеся на стандарт, предлагают записывать такой код?
P.S. Дублирование кода не предлагать!
← →
wicked © (2013-09-25 20:54) [1]1. return из внутреннего блока - плохо
лучше заведи переменную result, присваивай ей что нужно, а в конце делай return result - так не будет предупреждений компилятора
2. избавься от finally;
если нужно освобождать память, то лучше завернуть это в какой-либо smart pointer; или напиши свою обертку в стиле RAII
заодно и можно будет использовать нормальные try/catch, а не костыли
а вообще - приведи весь код функции, а не маленький, ничего не значащий кусочек
← →
ProgRAMmer Dimonych © (2013-09-25 21:13) [2]> 1. return из внутреннего блока - плохо
> лучше заведи переменную result, присваивай ей что нужно,
> а в конце делай return result - так не будет предупреждений
> компилятора
Предупреждение как раз если блок оставить пустым: о том, что некоторые ветви не возвращают значения.
---LPTSTR CSomeClass::_LoadFile(LPCTSTR lpszFileName)
{
LPTSTR pBuf;
HANDLE hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == hFile)
return NULL;
__try
{
DWORD dwSizeLow, dwSizeHigh;
dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
if (INVALID_FILE_SIZE == dwSizeLow)
{
if (NO_ERROR != GetLastError())
return NULL;
}
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (0 == hMapping)
return NULL;
__try
{
LPCSTR pData = (LPCSTR)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
if (NULL == pData)
return NULL;
__try
{
UINT CodePage = CP_ACP;
// <Много_кода>
// Определение кодировки с помещением Codepage identifier в CodePage
// </Много_кода>
DWORD dwBufSize = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, pData, dwSizeLow, NULL, 0);
if (ERROR_NO_UNICODE_TRANSLATION == GetLastError())
return NULL;
pBuf = new TCHAR[dwBufSize + 1];
__try
{
MultiByteToWideChar(CodePage, 0, pData, dwSizeLow, pBuf, dwBufSize);
pBuf[dwBufSize] = "\0";
return pBuf;
}
__except(delete[] pBuf, EXCEPTION_CONTINUE_SEARCH) { return NULL; }
}
__finally
{
UnmapViewOfFile(pData);
}
}
__finally
{
CloseHandle(hMapping);
}
}
__finally
{
CloseHandle(hFile);
}
}
---
> 2. избавься от finally;
> если нужно освобождать память, то лучше завернуть это в
> какой-либо smart pointer; или напиши свою обертку в стиле
> RAII
> заодно и можно будет использовать нормальные try/catch,
> а не костыли
Совсем не в восторге от идеи писать классы вокруг хэндлов: слишком круто для того, чтобы получить один раз получить хэндл и один раз его же освободить. В данном случае они будут костылями ещё покруче, чем __try.
← →
Anatoly Podgoretsky © (2013-09-25 21:54) [3]Может до холокоста?
← →
Mystic © (2013-09-25 22:10) [4]
> Совсем не в восторге от идеи писать классы вокруг хэндлов:
> слишком круто для того, чтобы получить один раз получить
> хэндл и один раз его же освободить. В данном случае они
> будут костылями ещё покруче, чем __try.
__try это вообще не C++, это Microsoft specific.
А так finally не ввели как раз из-за того, что такое поведение дублирует поведение деструкторов.
Или юзай BOOST_SCOPE_EXIT
http://www.boost.org/doc/libs/1_50_0_beta1/libs/scope_exit/doc/html/BOOST_SCOPE_EXIT.html
← →
DVM © (2013-09-25 22:15) [5]
> ProgRAMmer Dimonych © (25.09.13 21:13) [2]
> Совсем не в восторге от идеи писать классы вокруг хэндлов
не пиши, возьми boost - там уже все написали.
← →
ProgRAMmer Dimonych © (2013-09-25 22:42) [6]> [3] Anatoly Podgoretsky © (25.09.13 21:54)
> Может до холокоста?
Ну что ж я, холокост от localhost"а не отличу? :)
> [4] Mystic © (25.09.13 22:10)
> А так finally не ввели как раз из-за того, что такое поведение дублирует поведение деструкторов.
Да-да, я почитал, что на этот счёт думает Страуструп. Имея некоторый опыт борьбы с C++, не удивился. Имея некоторый опыт вообще — грязно выругался. Это при том, что и раньше знал, что нормального finally там нет.
> [4] Mystic © (25.09.13 22:10)
> Или юзай BOOST_SCOPE_EXIT
> [5] DVM © (25.09.13 22:15)
> не пиши, возьми boost - там уже все написали.
Не-не-не, коллеги, и не уговаривайте! Для маленькой, но очень гордой программки тащить монстра, для сборки которого у меня не хватит свободного места на жёстком диске, — лучше сразу пристрелите :)
← →
Mystic © (2013-09-26 11:24) [7]
> Для маленькой, но очень гордой программки тащить монстра,
> для сборки которого у меня не хватит свободного места на
> жёстком диске, — лучше сразу пристрелите :)
Ну так возьми идею.
← →
Anatoly Podgoretsky © (2013-09-26 11:48) [8]
> лучше сразу пристрелите
А это идея.
← →
jack128_ (2013-09-26 12:35) [9]
> Совсем не в восторге от идеи писать классы вокруг хэндлов:
> слишком круто для того, чтобы получить один раз получить
> хэндл и один раз его же освободить. В данном случае они
> будут костылями ещё покруче, чем __try.
Это в в дельфи классы/объекты - это некая тяжелая конструкция, несущая нехилый оверхер по памяти и производительности. В С++ - все не так. Учи язык, и не тяни в него свои дельфийские стереотипы.
← →
jack128_ (2013-09-26 12:40) [10]кстати для данной задачи свою RAII обертку не обязательно писать, можно стандартный unique_ptr использовать, подсунув ему свой Deleter
← →
Anatoly Podgoretsky © (2013-09-26 12:52) [11]
> jack128_ (26.09.13 12:35) [9]
хер говоришь :-)
← →
ProgRAMmer Dimonych © (2013-09-26 13:38) [12]> Это в в дельфи классы/объекты - это некая тяжелая конструкция,
> несущая нехилый оверхер по памяти и производительности.
> В С++ - все не так. Учи язык, и не тяни в него свои дельфийские
> стереотипы.
Замечание про C++ way принимается, но http://ru.wikipedia.org/wiki/Бритва_Оккама же. Плодить сущности, которые просто дублируют уже существующие своими Фаберже в профиль…
А вот интересный вопрос: если при выходе из процедуры нужно сделать запись в лог, используя данные из нескольких таких вот RAII-style классов, — чей деструктор будет выполнять эту запись в лог? Класс CWriteToLogForThisAwesomeProcedure?
← →
jack128_ (2013-09-26 13:56) [13]
> А вот интересный вопрос: если при выходе из процедуры нужно
> сделать запись в лог, используя данные из нескольких таких
> вот RAII-style классов, — чей деструктор будет выполнять
> эту запись в лог? Класс CWriteToLogForThisAwesomeProcedure?
>
этот конкретный пример задачи приведи. можно в виде дельфийского кода.
> Замечание про C++ way принимается, но http://ru.wikipedia.
> org/wiki/Бритва_Оккама же. Плодить сущности, которые просто
> дублируют уже существующие своими Фаберже в профиль…
это ты про finally ? Абсолютно верно, в с++ он абсолютно лишний, ибо дублирует RAII. Тебе об этом уже говорили.
Вообще RAII обертка на handle"ом - это первое, что должно писаться, если на WinApi взялся. Да и MMF в отдельный класс нужно завернуть.
> хер говоришь :-)
хер - это "херь"??
← →
Sergey Masloff (2013-09-26 16:28) [14]jack128_ (26.09.13 13:56) [13]
>> хер говоришь :-)
>хер - это "херь"??
а кто сказал
>Это в в дельфи классы/объекты - это некая тяжелая конструкция, несущая нехилый оверхер по памяти
мне кстати тоже понравилось возьму на вооружение
;-)
← →
ProgRAMmer Dimonych © (2013-09-26 23:08) [15]> этот конкретный пример задачи приведи. можно в виде дельфийского
> кода.
Красивый пример придумывать времени нет. Навскидку пусть будет, скажем, дебажная версия какой-нибудь софтины, пишущая в лог отладочную информацию о ресурсах.procedure ...
var
h1, h2: TResource; // Какие-то ресурсы, которые нужно освобождать и которые в C++ положено оборачивать классами
...
begin
try
h1 := GetResource(...);
h2 := GetResource(...);
if a = b then
begin
// Ещё несколько вложенных if
if ErrorCondition then
begin
Result := ERROR_SOMETHING_HAPPENED;
Exit;
end;
// ...
end;
finally
WriteToLog("Procedure exited. Allocated resources contained the following data: ", GetResourceData(h1), GetResourceData(h2));
FreeResource(h1);
FreeResource(h2);
end;
end;
А вообще даже вот просто залоггировать выход из процедуры (и нормальный, и по исключению), не дублируя код и не усложняя его же, чтобы сделать одну точку выхода.
> > Замечание про C++ way принимается, но http://ru.wikipedia.
> > org/wiki/Бритва_Оккама же. Плодить сущности, которые просто
>
> > дублируют уже существующие своими Фаберже в профиль…
>
> это ты про finally ? Абсолютно верно, в с++ он абсолютно
> лишний, ибо дублирует RAII. Тебе об этом уже говорили.
> Вообще RAII обертка на handle"ом - это первое, что должно
> писаться, если на WinApi взялся. Да и MMF в отдельный класс
> нужно завернуть.
Это я про те классы, в которые предлагается заворачивать. У меня есть сущность: хэндл. У неё есть определённый интерфейс (функции WinAPI), есть внутренняя реализация. Но мне предлагается её завернуть в ещё одну сущность, со своим интерфейсом, своей реализацией, только для того, чтобы «красиво» освободить ресурс. Причём освободить мне его нужно в одном-единственном месте в коде. Зачем простую операцию, которая, считается, даже зафейлиться не может, превращать в целый метод целого класса?
Внезапно, не зря finally-таки суют в C++: одна простая новая конструкция на уровне компилятора, чтобы лаконично выразить простую логику освобождения ресурса, против десятка классов в коде, пытающихся рвать гланды через прямую кишку, потому что «здесь так заведено». В C#, PHP и других языках (тысячи их!) вообще вопрос освобождения ресурса для программиста не стоит, но даже там finally в наличии, хотя логика для локальных переменных та же: вышел из области видимости — освобождён.
← →
jack128_ (2013-09-27 11:45) [16]
> Навскидку пусть будет, скажем, дебажная версия какой-нибудь
> софтины, пишущая в лог отладочную информацию о ресурсах.
>
какой то совсем хреновый пример. Что произойдет, если GetResource или GetResourceData кинет исключение?? AV ?
в плюсах я б написал примерно так
int main() {
// your code goes here
using ResourcePtr = std::unique_ptr<void, void (&) (void*)>;
ResourcePtr h1(GetResource(), FreeResource);
ResourcePtr h2(GetResource(), FreeResource);
auto logger = scope_exit([&]() { // самапальный аналог BOOST_SCOPE_EXIT
std::cout << "Procedure exited. Allocated resources contained the following data: "
<< GetResourceData(h1.get()) << GetResourceData(h2.get()) << std::endl;
});
// твои if"ы и тд т тп..
return 0;
}
этот код гораздо надежнее твоего, здесь код корректно отработает при любых исключениях
> Причём освободить мне его нужно в одном-единственном месте
> в коде.
сказки не надо рассказывать. если ты полез в WinApi, то хендлы тебе направо и налево придется освобождать.
> Внезапно, не зря finally-таки суют в C++
Только в твоих мечтах. В С++11 такого предложения не было. Сейчас в С++14 обсуждает, опять таки нету предложения.
> В C#, PHP и других языках (тысячи их!) вообще вопрос освобождения
> ресурса для программиста не стоит
То есть на C#/PHP и других языках в аналогичном коде FreeResource сам собой вызовется?? Срочно пиши статью, премия Тьюринга тебе обеспечена :-D
← →
ProgRAMmer Dimonych © (2013-09-27 18:12) [17]> То есть на C#/PHP и других языках в аналогичном коде FreeResource
> сам собой вызовется?? Срочно пиши статью, премия Тьюринга
> тебе обеспечена :-D
Внезапно, в PHP-таки файл закроется автоматом, ибо подсчёт ссылок: http://php.net/manual/ru/language.types.resource.php Стоит полюбопытствовать, прежде чем переходить на личности.
← →
Rouse_ © (2013-09-27 18:46) [18]
> ProgRAMmer Dimonych © (25.09.13 21:13) [2]
Зачем переносить Delphi-style в ся?
Выглядит страшновато...
Во всем приведенном коде все наведенные SEH избыточны...
← →
Rouse_ © (2013-09-27 18:52) [19]зы: дополню, в дельфе данный стиль существует из-за того что практически каждый вызов внутрь VCL может привести к вызову raise, а в сях такие ситуации четко обговорены MSDN и стало быть повсеместное использование SEH фреймов, выглядит немного глупо
← →
ProgRAMmer Dimonych © (2013-09-27 21:58) [20]> [19] Rouse_ © (27.09.13 18:52)
Внутри используется процедура, которая в дальнейшем может претерпевать серьёзные изменения. И в том числе начать броать исключения. Это дань сопровождаемости и только лишь.
← →
Rouse_ © (2013-09-27 23:28) [21]значит нужно лишь ее перекрытие
← →
| (2013-09-28 01:49) [22]
> Внезапно, в PHP-таки файл закроется автоматом, ибо подсчёт
> ссылок
почему php не был выбран языком реализации задачи?
← →
ProgRAMmer Dimonych © (2013-09-28 18:08) [23]> [22] | (28.09.13 01:49)
Потому что язык реализации оговорен заказчиком.
← →
ProgRAMmer Dimonych © (2013-09-28 18:09) [24]P.S. Ну и к тому же некузяво desktop-софтину писать на PHP.
← →
| (2013-09-29 04:08) [25]
> Потому что язык реализации оговорен заказчиком.
тогда принимай правила игры, или не берись за задачу
← →
| (2013-09-29 04:09) [26]зы
я уверен на 100%, что заказчик не будет рад ms-like finally
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2014.03.16;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.009 c