Здравствуйте, Caracrist, Вы писали:
C>enum CustomResultCode
Не узрел где этот тип используется дальше по тексту.
C> CustomResult_info_SUCCESS = 0, C> HRESULT_code = 0,
= 0 не нужен.
C> enum CodeType
Зачем это перечисление?
Здравствуйте, Caracrist, Вы писали:
C>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>Поделитесь своим опытом, у кого есть... Что из этого получается со временем?
Здравствуйте, remark, Вы писали: R>Здравствуйте, Caracrist, Вы писали: C>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем? R>Рекомендую поглядеть вот это: R>http://www.rsdn.ru/forum/cpp/3775662.1.aspx
Здравствуйте, Caracrist, Вы писали:
C>>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем?
R>>Рекомендую поглядеть вот это: R>>http://www.rsdn.ru/forum/cpp/3775662.1.aspx
Здравствуйте, Caracrist, Вы писали:
C>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>Решил сделать вот так:
C>
C>enum CustomResultCode
C>{
C> CustomResult_info_SUCCESS = 0,
C> //Add more CustomResult_info_*
C> //Add more CustomResult_error_*
C> //Add more CustomResult_exception_*
C>};
C>struct Result
C>{
C> enum CodeType
C> {
C> HRESULT_code = 0,
C> NTSTATUS_code,
C> LastError_code,
C> Custom_code
C> };
C> CodeType type;
C> LONG code;
C>};
C>
C>Поделитесь своим опытом, у кого есть... Что из этого получается со временем?
Из последнего что мне придумалось и удалсь реализовать:
struct SourceCodeNotch
{
const char* fileName;
unsigned lno;
const char* funcName;
public:
SourceCodeNotch(const char* fileName, unsigned lno, const char* funcName)
{ // очевидно, что
}
};
struct Status
{
typedef int Code;
enum
{
Ok,
GenericError,
IllegalStateError,
IllegalArgumentError,
// добавить по вкусу
...
}
class Error: std::exception // не обязательно, но весьма полезно
{
const Code code_;
const SourceCodeNotch src_;
public:
Error(const SourceCodeNotch& src, Code code): src_(src), code_(code)
{
}
};
static void
check(const SourceCodeNotch& src, Code code)
{
if (Ok != code)
{
throw Error(src, code);
}
}
};
class NoThrow {};
#define CREATE_SOURCE_CODE_NOTCH SourceCodeNotch(__FILE__, __LINE__, __FUNCTION__)
#define CHECK_STATUS(code) Status::check(CREATE_SOURCE_CODE_NOTCH, (code))
// Все функции овормляем так:
Status::Code
doSomething(const NoThrow&);
Status::Code
getSomething(const NoThrow&, int& res /* output parameter */);
#include"generated_api.h"
generated_api.h — файлец, который у меня генерит питоновский скрипт из исходного заголовка, будет примерно такой:
inline void
doSomething()
{
CHECK_STATUS(doSomething(NoThrow()));
}
inline int
getSomething()
{
int res;
CHECK_STATUS(getSomething(NoThrow(), res));
return res;
}
Убивается сразу много зайцев:
1. имеем версию интерфейса с кодами возврата и без исключений;
2. имеем версию интерфейса с исключениями;
3. силы на написание и поддержку тратим только на одну версию интерфейса.
Самое муторное — написать скрипт который будет парсить ваши С++ заголовки. Если сейчас лень писать скрипт — можно отложить на потом, когда будет нужда в интерфейсе с исключениями.
Еще один момент — код возврата желательно сделать sizeof(int), в противном случае получите проблемы с интероперабельностью вашего api, если он будет торчать из dll: каждый компилятор имеет свое представление о том, как передавать из функции возвращаемое значение, если оно не влезает в регистр eax (справедливо для x86).
A>struct SourceCodeNotch
A>{
A> const char* fileName;
A> unsigned lno;
A> const char* funcName;
A>public:
A> SourceCodeNotch(const char* fileName, unsigned lno, const char* funcName)
A> { // очевидно, что
A> }
A>};
у мя также имеется подобный классик
template <
typename File = const char*
, typename Line = File
, typename Function = File
>
class basic_location
{
// понятно что тут... ;)
};
// и typedef basic_location<const char*, const char*, const char*> location;
ибо, единственная разумная операция над __LINE__ это вывод на печать (или кто-то таки делает над ним арифмтические действия?? %) -- спрашивается зачем иметь его целочисленным типом, чтобы потом конвертить в строку при печати, когда можо сразу иметь его строкой??... но класс сделан шаблонным т.к. например апач-девелоперы накодили API в котором line это int... но во всех остальных проектах я использую данный typedef...
A>Убивается сразу много зайцев: A>1. имеем версию интерфейса с кодами возврата и без исключений; A>2. имеем версию интерфейса с исключениями; A>3. силы на написание и поддержку тратим только на одну версию интерфейса.
единственный, пока найденый мной, минус такого подхода:
если мы обернули таким образом функцию со сложной логикой работы, подразумевающую возврат какого-либо кода ошибки более чем в одном случае (ну тоесь допустим там много разнообразных проверок по ходу дела, но код возврата всегда один и тотже) -- оч трудно буит понять где всетки случилась ошибка т.к. SourceCodeNotch нам реально не поможет в этом...
A>Самое муторное — написать скрипт который будет парсить ваши С++ заголовки. Если сейчас лень писать скрипт — можно отложить на потом, когда будет нужда в интерфейсе с исключениями.
мда это риальна пугает... не хотелось бы писать парсер С++ для того чтоб распарсить таки вские шаблонные навороты типа boost::enable_if'ов, шаблонных параметров шаблонов, компаил таймных сиквенсов & etc...
жаль что gccxml в недоразвитом состоянии и не парсит шаблоны ;(
Здравствуйте, zaufi, Вы писали:
Z>ибо, единственная разумная операция над __LINE__ это вывод на печать (или кто-то таки делает над ним арифмтические действия?? %) -- спрашивается зачем иметь его целочисленным типом, чтобы потом конвертить в строку при печати, когда можо сразу иметь его строкой??... но класс сделан шаблонным т.к. например апач-девелоперы накодили API в котором line это int... но во всех остальных проектах я использую данный typedef...
Согласен, шаблончик сипатичный
A>>Убивается сразу много зайцев: A>>1. имеем версию интерфейса с кодами возврата и без исключений; A>>2. имеем версию интерфейса с исключениями; A>>3. силы на написание и поддержку тратим только на одну версию интерфейса.
Z>единственный, пока найденый мной, минус такого подхода: Z>если мы обернули таким образом функцию со сложной логикой работы, подразумевающую возврат какого-либо кода ошибки более чем в одном случае (ну тоесь допустим там много разнообразных проверок по ходу дела, но код возврата всегда один и тотже) -- оч трудно буит понять где всетки случилась ошибка т.к. SourceCodeNotch нам реально не поможет в этом...
Да, SourceCodeNotch наружу из такой функции не вытягивается. Но, imho, логирование вполне решает проблему. Не вижу особого смысла в вызывающей функции знать о точном месте где случилась ошибка, не пользователей же этой инфомацией пугать.
A>>Самое муторное — написать скрипт который будет парсить ваши С++ заголовки. Если сейчас лень писать скрипт — можно отложить на потом, когда будет нужда в интерфейсе с исключениями.
Z>мда это риальна пугает... не хотелось бы писать парсер С++ для того чтоб распарсить таки вские шаблонные навороты типа boost::enable_if'ов, шаблонных параметров шаблонов, компаил таймных сиквенсов & etc...
Навороты все в сад, т.е. в реализацию, а интерфейс оставить простым и красивым. Пусть все думают, что внутри все так же
Здравствуйте, Caracrist, Вы писали:
C>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>Решил сделать вот так: C>... C>Поделитесь своим опытом, у кого есть... Что из этого получается со временем?
Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, alsemm, Вы писали:
Z>>единственный, пока найденый мной, минус такого подхода: Z>>если мы обернули таким образом функцию со сложной логикой работы, подразумевающую возврат какого-либо кода ошибки более чем в одном случае (ну тоесь допустим там много разнообразных проверок по ходу дела, но код возврата всегда один и тотже) -- оч трудно буит понять где всетки случилась ошибка т.к. SourceCodeNotch нам реально не поможет в этом... A>Да, SourceCodeNotch наружу из такой функции не вытягивается. Но, imho, логирование вполне решает проблему. Не вижу особого смысла в вызывающей функции знать о точном месте где случилась ошибка, не пользователей же этой инфомацией пугать.
интересна, а зачем она вообще тогда там (в исключении) есть?
мой типичный сценарий таков:
* к исключениям всегда аттачится location (через параметр конструктора) и backtrace (создается автоматически в базовом конструкторе исключения)
* если verbosity level >= debug, то при выводе ошибки в лог\экран распечатывается также аттачнутая дебагерная инфа (т.е. то что может помочь разработчику быстро локализовать проблему)... т.е. обчно пользователь не включает verbosity level выше info и ничего ужастного не видит... но если возникают проблемы, то в багрепорт вкладывается лог с максимальным levelом.
... ну а так в целом, да... логирование решает проблему... когда оно есть -- т.е. если вдруг в описаной в моем первом посте сложной функции возникает проблема, и ты точно не знаешь какой из return'ов вернул код ошибки, то нада расставлять спам перед каждым ... %)
Здравствуйте, zaufi, Вы писали:
Z>Здравствуйте, alsemm, Вы писали:
Z>>>единственный, пока найденый мной, минус такого подхода: Z>>>если мы обернули таким образом функцию со сложной логикой работы, подразумевающую возврат какого-либо кода ошибки более чем в одном случае (ну тоесь допустим там много разнообразных проверок по ходу дела, но код возврата всегда один и тотже) -- оч трудно буит понять где всетки случилась ошибка т.к. SourceCodeNotch нам реально не поможет в этом... A>>Да, SourceCodeNotch наружу из такой функции не вытягивается. Но, imho, логирование вполне решает проблему. Не вижу особого смысла в вызывающей функции знать о точном месте где случилась ошибка, не пользователей же этой инфомацией пугать.
Z>интересна, а зачем она вообще тогда там (в исключении) есть?
Чтобы в лог ее записать
Z>мой типичный сценарий таков: Z>* к исключениям всегда аттачится location (через параметр конструктора) и backtrace (создается автоматически в базовом конструкторе исключения) Z>* если verbosity level >= debug, то при выводе ошибки в лог\экран распечатывается также аттачнутая дебагерная инфа (т.е. то что может помочь разработчику быстро локализовать проблему)... т.е. обчно пользователь не включает verbosity level выше info и ничего ужастного не видит... но если возникают проблемы, то в багрепорт вкладывается лог с максимальным levelом.
Z>... ну а так в целом, да... логирование решает проблему... когда оно есть -- т.е. если вдруг в описаной в моем первом посте сложной функции возникает проблема, и ты точно не знаешь какой из return'ов вернул код ошибки, то нада расставлять спам перед каждым ... %)
Cпециально что-то расставлять не надо, можно так:
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, Caracrist, Вы писали:
C>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>Решил сделать вот так: C>>... C>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем? V>Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток.
Угу, и вместо одного вызова для выполнения какой-то операции нужно делать два, чтобы проверить, а успешно-ли завершился первый. Да, еще надо не забыть в реализации методов вызывать SetLastError(). Еще гарантирован срач про то, надо-ли вызывать SetLastError(), чтобы сбросить код ошибки, если он есть внутри реализации или достаточно просто дернуть SetLastError() когда ошибка произойдет. А на вывызвающей стороне 100% кто-нибудь забудет вызвать GetLastError() — я гаратнтирую это (C). Потом надо написать мануал про то как пользоваться таким api и мануал как его писать. И убедится, что эти мануалы прочитали. Вообщем работа будет у всех, а профита не будет ни у кого
Здравствуйте, alsemm, Вы писали:
C>>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>>Решил сделать вот так: C>>>... C>>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем? V>>Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток. A>Угу, и вместо одного вызова для выполнения какой-то операции нужно делать два, чтобы проверить, а успешно-ли завершился первый. Да, еще надо не забыть в реализации методов вызывать SetLastError(). Еще гарантирован срач про то, надо-ли вызывать SetLastError(), чтобы сбросить код ошибки, если он есть внутри реализации или достаточно просто дернуть SetLastError() когда ошибка произойдет. А на вывызвающей стороне 100% кто-нибудь забудет вызвать GetLastError() — я гаратнтирую это (C). Потом надо написать мануал про то как пользоваться таким api и мануал как его писать. И убедится, что эти мануалы прочитали. Вообщем работа будет у всех, а профита не будет ни у кого
А то что это практикой проверено конечно не в счёт?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Здравствуйте, alsemm, Вы писали:
C>>>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>>>Решил сделать вот так: C>>>>... C>>>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем? V>>>Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток. A>>Угу, и вместо одного вызова для выполнения какой-то операции нужно делать два, чтобы проверить, а успешно-ли завершился первый. Да, еще надо не забыть в реализации методов вызывать SetLastError(). Еще гарантирован срач про то, надо-ли вызывать SetLastError(), чтобы сбросить код ошибки, если он есть внутри реализации или достаточно просто дернуть SetLastError() когда ошибка произойдет. А на вывызвающей стороне 100% кто-нибудь забудет вызвать GetLastError() — я гаратнтирую это (C). Потом надо написать мануал про то как пользоваться таким api и мануал как его писать. И убедится, что эти мануалы прочитали. Вообщем работа будет у всех, а профита не будет ни у кого V>А то что это практикой проверено конечно не в счёт?
SetLastError/GetLastError в Win API — это не замена кодов возврата, а их дополнение, для получения расширенной информации об ошибках. Зачем этот костыль городить, если есть возможность спроектировать систему уведомления об ошибках с чистого листа?
Здравствуйте, Caracrist, Вы писали:
C>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>Решил сделать вот так:
C>
C>enum CustomResultCode
C>{
C> CustomResult_info_SUCCESS = 0,
C> //Add more CustomResult_info_*
C> //Add more CustomResult_error_*
C> //Add more CustomResult_exception_*
C>};
C>struct Result
C>{
C> enum CodeType
C> {
C> HRESULT_code = 0,
C> NTSTATUS_code,
C> LastError_code,
C> Custom_code
C> };
C> CodeType type;
C> LONG code;
C>};
C>
Разве могут LastError, HRESULT и NTSTATUS пересекаться ?
Разве нельзя вводить свои HRESULTы ?
А ещё: RtlNtStatusToDosError, HRESULT_FROM_NT, HRESULT_FROM_WIN32
Здравствуйте, alsemm, Вы писали:
C>>>>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями. C>>>>>Решил сделать вот так: C>>>>>... C>>>>>Поделитесь своим опытом, у кого есть... Что из этого получается со временем? V>>>>Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток. A>>>Угу, и вместо одного вызова для выполнения какой-то операции нужно делать два, чтобы проверить, а успешно-ли завершился первый. Да, еще надо не забыть в реализации методов вызывать SetLastError(). Еще гарантирован срач про то, надо-ли вызывать SetLastError(), чтобы сбросить код ошибки, если он есть внутри реализации или достаточно просто дернуть SetLastError() когда ошибка произойдет. А на вывызвающей стороне 100% кто-нибудь забудет вызвать GetLastError() — я гаратнтирую это (C). Потом надо написать мануал про то как пользоваться таким api и мануал как его писать. И убедится, что эти мануалы прочитали. Вообщем работа будет у всех, а профита не будет ни у кого V>>А то что это практикой проверено конечно не в счёт? A>SetLastError/GetLastError в Win API — это не замена кодов возврата, а их дополнение, для получения расширенной информации об ошибках. Зачем этот костыль городить, если есть возможность спроектировать систему уведомления об ошибках с чистого листа?
Это нормальная и простая замена кодам возврата, в отличии от какой-то системы уведомлений. Тем более иногда не имеется возможности изменять интерфейс функций, а подменить реализацию экспортов своей надо, как вы в этом случае будете возвращать коды возврата? Писать фреймворк? А не проще сэкспортировать две новые функции и всё?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Это нормальная и простая замена кодам возврата, в отличии от какой-то системы уведомлений.
Вы предлагаете отказаться вообще от кодов возварата, что-ли и писать вот так ?:
void DoSomething();
DoSomething();
if (GetLastError() != NO_ERROR)
{ // чего-то делать
}
V>Тем более иногда не имеется возможности изменять интерфейс функций, а подменить реализацию экспортов своей надо, как вы в этом случае будете возвращать коды возврата? Писать фреймворк? А не проще сэкспортировать две новые функции и всё?
Исходнное сообщение ТС:
допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями.
что как бы намекает, что никакого интерфейса, к которому надо пристроить костыли еще нет. Вы предлагаете начать с костылей, потому что это, видите-ли "практикой проверено". Посмотрите на COM, там своя система уведомлений простая и удобная — HRESULT. И никаких SetLastError/GetLastError.
Здравствуйте, alsemm, Вы писали:
V>>Это нормальная и простая замена кодам возврата, в отличии от какой-то системы уведомлений. A>Вы предлагаете отказаться вообще от кодов возварата, что-ли и писать вот так ?: A>
A>void DoSomething();
A>DoSomething();
A>if (GetLastError() != NO_ERROR)
A>{ // чего-то делать
A>}
A>
Где вы видели что я сказал что надо отказаться от кодов возврата?
V>>Тем более иногда не имеется возможности изменять интерфейс функций, а подменить реализацию экспортов своей надо, как вы в этом случае будете возвращать коды возврата? Писать фреймворк? А не проще сэкспортировать две новые функции и всё? A>Исходнное сообщение ТС: A>
A>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями.
Речь шла про вашу некую таинственную "систему уведомлений" в противовес которой я и поставил простую реализацию из двух функций.
A>что как бы намекает, что никакого интерфейса, к которому надо пристроить костыли еще нет. Вы предлагаете начать с костылей, потому что это, видите-ли "практикой проверено". Посмотрите на COM, там своя система уведомлений простая и удобная — HRESULT. И никаких SetLastError/GetLastError.
Ну на вкус и цвет..
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, Vain, Вы писали:
V>Где вы видели что я сказал что надо отказаться от кодов возврата?
Вот тут:
Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток.
Ответьте на вопрос: если функции ничего не возвращают, то как узнать, что функция типа void foo() отработала успешно?
V>>>Тем более иногда не имеется возможности изменять интерфейс функций, а подменить реализацию экспортов своей надо, как вы в этом случае будете возвращать коды возврата? Писать фреймворк? А не проще сэкспортировать две новые функции и всё? A>>Исходнное сообщение ТС: A>>
A>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями.
V>Речь шла про вашу некую таинственную "систему уведомлений" в противовес которой я и поставил простую реализацию из двух функций.
Моя "таинственная система уведомлений" вовсе не "некая" — ее эскиз приведен в моем первом посте в это теме.
Свои соображения по поводу "простоты" SetLastError/GetLastError я уже изложил. Кратко еще раз — она не простая, а примитивная и пользоваться ей неудобно.
Здравствуйте, alsemm, Вы писали:
V>>Где вы видели что я сказал что надо отказаться от кодов возврата? A>Вот тут: A>
A>Далеко ходить не надо — Win API SetLastError/GetLastError. Делаете себе тикие-же функции с хранением кода в thread storage. И функции ничего не возвращают и код возврата сохраняется на поток.
Вы разницу между утверждением и предложением чуствуете? A>Ответьте на вопрос: если функции ничего не возвращают, то как узнать, что функция типа void foo() отработала успешно?
Вы же сами недавно ответили на этот вопрос с объяснением чего и как.
V>>>>Тем более иногда не имеется возможности изменять интерфейс функций, а подменить реализацию экспортов своей надо, как вы в этом случае будете возвращать коды возврата? Писать фреймворк? А не проще сэкспортировать две новые функции и всё? A>>>Исходнное сообщение ТС: A>>>
A>>>допустим у меня нет выбора и нужно пользоваться кодами возврата, а не исключениями.
V>>Речь шла про вашу некую таинственную "систему уведомлений" в противовес которой я и поставил простую реализацию из двух функций. A>Моя "таинственная система уведомлений" вовсе не "некая" — ее эскиз приведен в моем первом посте в это теме. A>Свои соображения по поводу "простоты" SetLastError/GetLastError я уже изложил. Кратко еще раз — она не простая, а примитивная и пользоваться ей неудобно.
В первый раз слышу чтобы примитивной системой было неудобно пользоваться.
А набором макросов (а в их код лезть придётся) и скриптом для генерации (и туда лезть тоже придётся) наверно по-вашему пользоваться гораздо удобнее?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]