Здравствуйте, remark, Вы писали:
R>Это не то. R>VERIFY не везде есть.
#define REMARK_VERIFY
R>VERIFY выдаёт мессаджбокс.
#define REMARK_VERIFY
R>В регистрах искать не очень круто при прочих равных. R>В регистре значение будет очень не долго, а в дампе его вообще не будет.
#define REMARK_VERIFY(x) LBRACE auto tmp = x; assert(x); RBRACE
#define LBRACE do {
#define RBRACE } while(false)
R>Иногда со значением вообще ничего не надо делать, просто что бы было. $err надо успеть сделать, и вообще его надо делать.
Здравствуйте, remark, Вы писали:
R>З.ы. volatile важен, т.к. обычно его забываешь ставить, и потом в релизе до истины уже не докапаешься.
Идея сохранить удобства дебага в релизе с помощью volatile прикольная — все равно syscall штука недешевая так что запись в переменную считай бесплатно.
Идея не обрабатывать ошибки в релизе достойна порки.
Я не настаиваю на месадж боксах тк пишу и под линупс без гуя но альтернативы всегда есть — логи и тп. Даже если не собираетесь падать эта инфо может быть очень важна.
Отвечу сразу всем тут.
Во-первых, я не навязываю использование это штуки. Просто приём, сами смотрите нужно не нужно.
Во-вторых, не всегда можно логировать и даже не всегда можно вернуть ошибку. Вы смотрите со стороны кода конечного приложения, а если это, например, библиотека. Например, библиотека реализующая многопоточность из C1x. Логирование — это определенно не то, чего хочет пользователь от такой библиотека. Ошибки из некоторых функций вообще не вернуть (такая сигнатура), или не все можно отмапить (там очень маленький фиксированный список). И что делать в такой ситуации?
Зачем это всё? Зачем свой конструктор копии и зачем запрет присваивания?
Или фишка в том, что нельзя поменять? Тогда, по идее, нужен не operator T, а operator const T&
R>З.ы. volatile важен, т.к. обычно его забываешь ставить, и потом в релизе до истины уже не докапаешься.
Ну и название мне не нравится, конечно. Фраза
unused<DWORD> res = GetLastError();
checkError( res );
нифига не читабельная. Может как-то типа debug_variable назвать, например?
R>
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
А вообще, конечно, цель сократить одну строчку ложная.
Другое дело, что волотайл может быть в тему.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Зачем это всё? Зачем свой конструктор копии и зачем запрет присваивания? E>Или фишка в том, что нельзя поменять? Тогда, по идее, нужен не operator T, а operator const T&
думаю, чтобы подавить варнинг неиспользуемой переменной в релизе.
Здравствуйте, night beast, Вы писали:
NB>думаю, чтобы подавить варнинг неиспользуемой переменной в релизе.
Как-то это ненадёжно.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А вообще, конечно, цель сократить одну строчку ложная.
А что делать, если надо обернуть кучу WinAPI/POSIX, и таких мест дофига?
В паре месте написать лишнюю строчку нормально, но в десятках тоже как-то не очень имвхо...
В релизе переменная тоже нужна, что бы видеть в отладчике или в дампе.
К>В чём прикол с volatile, не понял. И почему нельзя по месту писать unused<volatile T>, если известно, что функция возвращает volatile?
Если переменная используется только в assert'е, или вообще не используется (просто хочется видеть значение в отладчике/дампе), то в релизе её либо вообще не будет, либо она будет замешана где-то в регистрах.
Если же объявлять как:
DWORD volatile err = GetLastError();
То она в релизе не только останется, но даже и отладчик скорее всего будет показывать корректное значение.
Здравствуйте, superlexx, Вы писали:
R>>template<typename T> class unused
S>Проще надо быть:
VERIFY(CloseHandle(x));
Если на результаты хочется посмотреть, то найдёте их в регистрах. GetLastError -- $err,hr в Watch
Это не то.
VERIFY не везде есть.
VERIFY выдаёт мессаджбокс.
В регистрах искать не очень круто при прочих равных.
В регистре значение будет очень не долго, а в дампе его вообще не будет.
Иногда со значением вообще ничего не надо делать, просто что бы было. $err надо успеть сделать, и вообще его надо делать.
Здравствуйте, Vamp, Вы писали:
R>>Иногда приходится писать код типа: V>Я уже всю голову сломал, но так и не понял, зачем такой код приходится писать?
V>Чтоза поведение обеспечивается?
чтобы Visual Studio не выдавал warning когда включен Level 4. Предупреждение будет, типа: «локальная переменная объявлена но не используется»
В>чтобы Visual Studio не выдавал warning когда включен Level 4. Предупреждение будет, типа: «локальная переменная объявлена но не используется»
А, спасибо, понял. Я бы правда скорее подавил предупреждение.
В>>чтобы Visual Studio не выдавал warning когда включен Level 4. Предупреждение будет, типа: «локальная переменная объявлена но не используется» V>А, спасибо, понял. Я бы правда скорее подавил предупреждение.
лучше этого не делать с помощью всяких подавителей иногда можно так и (логическую) ошибку пропустить.
R>Дабы сократить 1 строчку, подумалось:
...
R>А что делать, если надо обернуть кучу WinAPI/POSIX, и таких мест дофига?
Я использую несколько другой вариант, который сродни перловскому оператору die. У меня он бросает исключение, но в принципе может делать всё что угодно (включая запись в volatile, что, по-моему, абсолютно лишнее). Внизу только простой юнит тест. Реализация оставляется как упражнение читателю .
Здравствуйте, Vamp, Вы писали:
В>>чтобы Visual Studio не выдавал warning когда включен Level 4. Предупреждение будет, типа: «локальная переменная объявлена но не используется» V>А, спасибо, понял. Я бы правда скорее подавил предупреждение.
Да не, там немного другое — обеспечивается еще и невыкидывание этой переменной оптимизатором. Насколько я понял, чтобы в релизе можно было посмотреть ее значение. Лично я, впрочем, обычно предпочитаю логгирование, ну да случаи всякие бывают.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, remark, Вы писали:
R>Отвечу сразу всем тут. R>Во-первых, я не навязываю использование это штуки. Просто приём, сами смотрите нужно не нужно. R>Во-вторых, не всегда можно логировать и даже не всегда можно вернуть ошибку. Вы смотрите со стороны кода конечного приложения, а если это, например, библиотека. Например, библиотека реализующая многопоточность из C1x. Логирование — это определенно не то, чего хочет пользователь от такой библиотека. Ошибки из некоторых функций вообще не вернуть (такая сигнатура), или не все можно отмапить (там очень маленький фиксированный список). И что делать в такой ситуации?
Логировать точно не надо.
Очевидно что пользователи ограничены только спецификацией библиотеки, поэтому логично предположить что при желании пользователя изменить реализацию на другую поведение самой программы не должно измениться (при условии что реализация корректна). Можно, например начать кидать исключение (выставлять errno, и т.д.) и явно задокументировать это, но в этом случае пользователь станет привязанным к конкретной реализации (т.к. он потенциально готов к этому исключению и возможно будет его обрабатывать). Изменение контракта в этом случае — это прямое нарушение LSP с соответствующими последствиями. Выхода здесь два — не использовать механизмы которые могут привести к озвученной ситуации, либо все-таки свернуть возможные ошибки в более узкий класс, как того требует спецификация.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Логировать точно не надо. ЮЖ>Очевидно что пользователи ограничены только спецификацией библиотеки, поэтому логично предположить что при желании пользователя изменить реализацию на другую поведение самой программы не должно измениться (при условии что реализация корректна). Можно, например начать кидать исключение (выставлять errno, и т.д.) и явно задокументировать это, но в этом случае пользователь станет привязанным к конкретной реализации (т.к. он потенциально готов к этому исключению и возможно будет его обрабатывать). Изменение контракта в этом случае — это прямое нарушение LSP с соответствующими последствиями. Выхода здесь два — не использовать механизмы которые могут привести к озвученной ситуации, либо все-таки свернуть возможные ошибки в более узкий класс, как того требует спецификация.
Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
Тут теряется информация (иногда сводить придётся к void). Так чем же хуже ещё к этому и дать отлаживающему пользователю информацию в удобной форме?
Здравствуйте, remark, Вы писали:
R>Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
Хотя здесь еще один аспект есть, но он относится по большему счету к полноте спецификации — описание возможных побочных эффектов ("чистота" функций, сложность выполнения и т.п). Это может налагать дополнительные ограничения на реализацию.
R>Тут теряется информация (иногда сводить придётся к void). Так чем же хуже ещё к этому и дать отлаживающему пользователю информацию в удобной форме?
Ведет ли себя (библиотечная) функция в этом случае корректно (в рамках контракта)?
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Здравствуйте, remark, Вы писали:
R>>Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
ЮЖ>Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
Потому что они при этом не нарушают свой контракт.
R>>Тут теряется информация (иногда сводить придётся к void). Так чем же хуже ещё к этому и дать отлаживающему пользователю информацию в удобной форме?
ЮЖ>Ведет ли себя (библиотечная) функция в этом случае корректно (в рамках контракта)?
Я не вижу каким образом в контракте может быть специфицировано, что функция не должна создавать на стеке каких-то определенных переменных.
Здравствуйте, remark, Вы писали:
R>>>Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
ЮЖ>>Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
R>Потому что они при этом не нарушают свой контракт.
? "не использовать механизмы ... *И* свернуть ..." != "Механизм используется, ошибки свернуты"
R>>>Тут теряется информация (иногда сводить придётся к void). Так чем же хуже ещё к этому и дать отлаживающему пользователю информацию в удобной форме?
ЮЖ>>Ведет ли себя (библиотечная) функция в этом случае корректно (в рамках контракта)?
R>Я не вижу каким образом в контракте может быть специфицировано, что функция не должна создавать на стеке каких-то определенных переменных.
Я имею ввиду игнорирование вызовов CloseHandle/GetLastError/. Или ты говоришь о таких случаях:
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Здравствуйте, remark, Вы писали:
R>>>>Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
ЮЖ>>>Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
R>>Потому что они при этом не нарушают свой контракт.
ЮЖ>? "не использовать механизмы ... *И* свернуть ..." != "Механизм используется, ошибки свернуты"
В WinAPI НЕ используются механизмы, которые приводят к нарешению контракта *И* ошибки свёрнуты.
R>>>>Тут теряется информация (иногда сводить придётся к void). Так чем же хуже ещё к этому и дать отлаживающему пользователю информацию в удобной форме?
ЮЖ>>>Ведет ли себя (библиотечная) функция в этом случае корректно (в рамках контракта)?
R>>Я не вижу каким образом в контракте может быть специфицировано, что функция не должна создавать на стеке каких-то определенных переменных.
ЮЖ>Я имею ввиду игнорирование вызовов CloseHandle/GetLastError/. Или ты говоришь о таких случаях:
ЮЖ>
Здравствуйте, remark, Вы писали:
R>>>>>Это один выход — не использовать механизмы которые могут привести к озвученной ситуации *И* свернуть возможные ошибки в более узкий класс, как того требует спецификация.
ЮЖ>>>>Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
R>>>Потому что они при этом не нарушают свой контракт.
ЮЖ>>? "не использовать механизмы ... *И* свернуть ..." != "Механизм используется, ошибки свернуты"
R>В WinAPI НЕ используются механизмы, которые приводят к нарешению контракта *И* ошибки свёрнуты.
Не понимаю о чем ты... "Механизм используется, ошибки свернуты" — это один из способов реализации, которая удовлетворяет контракту.
ЮЖ>>Я имею ввиду игнорирование вызовов CloseHandle/GetLastError/. Или ты говоришь о таких случаях:
ЮЖ>>
R>Что-то типа такого... только надо ещё volatile добавить, иначе в релизе не будет работать.
В таком варианте — не вижу особого смысла, если же способ передачи подробной информации об ошибках в нижних слоях наверх действительно нужен — то тут нужно думать... Хотя сокрытие деталей — одна из причин введения дополнительных уровней абстракции.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>>>Почему *И*? Например, в том же winapi все коды ошибок можно свернуть к {успех, неудача}... Механизм используется, ошибки свернуты.
R>>>>Потому что они при этом не нарушают свой контракт.
ЮЖ>>>? "не использовать механизмы ... *И* свернуть ..." != "Механизм используется, ошибки свернуты"
R>>В WinAPI НЕ используются механизмы, которые приводят к нарешению контракта *И* ошибки свёрнуты.
ЮЖ>Не понимаю о чем ты... "Механизм используется, ошибки свернуты" — это один из способов реализации, которая удовлетворяет контракту.
А я на понимаю о чём. Ты написал "либо не использовать механизмы, которые приводят к нарушение контрактов". В WinAPI такие механихмы не используются. Теперь ты пишешь, что какой-то механизм используется. Какой? Где?
ЮЖ>>>Я имею ввиду игнорирование вызовов CloseHandle/GetLastError/. Или ты говоришь о таких случаях:
ЮЖ>>>
R>>Что-то типа такого... только надо ещё volatile добавить, иначе в релизе не будет работать.
ЮЖ>В таком варианте — не вижу особого смысла, если же способ передачи подробной информации об ошибках в нижних слоях наверх действительно нужен — то тут нужно думать... Хотя сокрытие деталей — одна из причин введения дополнительных уровней абстракции.
Здравствуйте, remark, Вы писали:
ЮЖ>>в том же winapi все коды ошибок можно свернуть к {успех, неудача}
ЮЖ>>Не понимаю о чем ты... "Механизм используется, ошибки свернуты" — это один из способов реализации, которая удовлетворяет контракту.
R>А я на понимаю о чём. Ты написал "либо не использовать механизмы, которые приводят к нарушение контрактов". В WinAPI такие механихмы не используются.
Я этого не говорил.
"В ... winapi все коды ошибок можно свернуть к {успех, неудача}":
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>в том же winapi все коды ошибок можно свернуть к {успех, неудача}
ЮЖ>>>Не понимаю о чем ты... "Механизм используется, ошибки свернуты" — это один из способов реализации, которая удовлетворяет контракту.
R>>А я на понимаю о чём. Ты написал "либо не использовать механизмы, которые приводят к нарушение контрактов". В WinAPI такие механихмы не используются.
ЮЖ>Я этого не говорил.
Я это говорю. А что там используются какие-то механизмы, которые нарушают контракты?
Вариант-то один — И не использовать механизмы, которые нарушают контракт, *И* сводить все ошибки к тому, что дано в контракте. И это неминуемо ведёт к потере информации.
R>Вариант-то один — И не использовать механизмы, которые нарушают контракт, *И* сводить все ошибки к тому, что дано в контракте. И это неминуемо ведёт к потере информации.
Ну отчего же. Можно использовать механизмы вроде errno — GetLastError.
Здравствуйте, Vamp, Вы писали:
R>>Вариант-то один — И не использовать механизмы, которые нарушают контракт, *И* сводить все ошибки к тому, что дано в контракте. И это неминуемо ведёт к потере информации.
V>Ну отчего же. Можно использовать механизмы вроде errno — GetLastError.
Это — тоже контакт. Если это не прописано в контракте, то нельзя. Ну или точнее — бессмысленно. То же самое, что я и предлагаю, только не удобно.
Здравствуйте, remark, Вы писали:
R>Вариант-то один — И не использовать механизмы, которые нарушают контракт, *И* сводить все ошибки к тому, что дано в контракте.
См. две первые реализации 'get' из предыдущего ответа. "Механизм" используется в двух реализациях, но тем не менее в одной есть нарушение контракта (именно по причине использования этого механизма), а в другой нет.
Здравствуйте, Vamp, Вы писали:
R>>Это — тоже контакт. Если это не прописано в контракте, то нельзя. Ну или точнее — бессмысленно.
V>Отчего же бессмысленно? Можно расширить функциональность, не нарушая контракта.
От того, что пользователи используют функциональность через контракт. Если в контракте этого нет, то это бессмысленно. Пользователь не знает ни о чём, кроме контракта.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Здравствуйте, remark, Вы писали:
R>>Вариант-то один — И не использовать механизмы, которые нарушают контракт, *И* сводить все ошибки к тому, что дано в контракте.
ЮЖ>См. две первые реализации 'get' из предыдущего ответа. "Механизм" используется в двух реализациях, но тем не менее в одной есть нарушение контракта (именно по причине использования этого механизма), а в другой нет.
И как оттуда вернуть ошибку "нет прав для выделения памяти" именно через такой контакт "возвращается указатель на int или 0"?
Никак. Там просто тупо давятся все ошибки.
R>От того, что пользователи используют функциональность через контракт. Если в контракте этого нет, то это бессмысленно. Пользователь не знает ни о чём, кроме контракта.
Ну от чего же? Допустим, у нас выходит новая версия библиотеки, которая поддерживает расширенную информацию об ошибках. Контракт нарушать нельзя в целях обратной совместимости. Введя дополнительную функцию можно обеспечить расширение функциональности без нарушения контракта.
Здравствуйте, remark, Вы писали:
ЮЖ>>См. две первые реализации 'get' из предыдущего ответа. "Механизм" используется в двух реализациях, но тем не менее в одной есть нарушение контракта (именно по причине использования этого механизма), а в другой нет.
R>И как оттуда вернуть ошибку "нет прав для выделения памяти" именно через такой контакт "возвращается указатель на int или 0"? R>Никак. Там просто тупо давятся все ошибки.
Давятся, т.к. на уровне контракта в общем случае невозможно специфицировать все возможные ошибки, которые могут возникнуть в реализации.
Здравствуйте, Vamp, Вы писали:
R>>От того, что пользователи используют функциональность через контракт. Если в контракте этого нет, то это бессмысленно. Пользователь не знает ни о чём, кроме контракта.
V>Ну от чего же? Допустим, у нас выходит новая версия библиотеки, которая поддерживает расширенную информацию об ошибках. Контракт нарушать нельзя в целях обратной совместимости. Введя дополнительную функцию можно обеспечить расширение функциональности без нарушения контракта.
Ты говоришь о ситуации, когда можно менять контракт. Тут действительно нет проблеим.
Я говорю о ситуации, когда контракт менять нельзя. Нужно решить в рамках данного контракта. И тут решений нет. Поэтому я и довольствуюсь тем, что разработчика при отладке кинет на нужный ассёрт, и у него будет вся необходимая информация под рукой. Всё лучше, чем без этого.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>См. две первые реализации 'get' из предыдущего ответа. "Механизм" используется в двух реализациях, но тем не менее в одной есть нарушение контракта (именно по причине использования этого механизма), а в другой нет.
R>>И как оттуда вернуть ошибку "нет прав для выделения памяти" именно через такой контакт "возвращается указатель на int или 0"? R>>Никак. Там просто тупо давятся все ошибки.
ЮЖ>Давятся, т.к. на уровне контракта в общем случае невозможно специфицировать все возможные ошибки, которые могут возникнуть в реализации.
R>Ты говоришь о ситуации, когда можно менять контракт. Тут действительно нет проблеим. R>Я говорю о ситуации, когда контракт менять нельзя.
Как правило, с практической точки зрения введение дополнительных функций не является нарушением контракта, так как не нарушает работу ранее существовавших приложений. Изменение же возвращаемого значения, безусловно, является.
Здравствуйте, Vamp, Вы писали:
R>>Ты говоришь о ситуации, когда можно менять контракт. Тут действительно нет проблеим. R>>Я говорю о ситуации, когда контракт менять нельзя.
V>Как правило, с практической точки зрения введение дополнительных функций не является нарушением контракта, так как не нарушает работу ранее существовавших приложений. Изменение же возвращаемого значения, безусловно, является.
Введение дополнительных функций конечно не является нарушением контракта, но и бессмысленно.
Интересно у кого раньше стек кончится...
R>Введение дополнительных функций конечно не является нарушением контракта, но и бессмысленно. R>Интересно у кого раньше стек кончится...
Такое ощущение, что ты меня не слышишь. Попробую объяснить на очень простом примере.
У тебя есть библиотека, вызывающая некоторое системное API. На момент разработки библиотеки API возврашало bool — success or failure. Соответствено, библиотечная функция тоже возвращала bool — предположим, собственных ошибок она породить не могла. В новой версии ОС API стало предоставлять дополнительные сведения об ошибках, и ты хочешь вернуть их пользователю.
Расширять возвращаемое значение нельзя — посыпятся старые приложения. Единственный выход — ввести дополнительную функцию возврата расширеной ошибки. Таким образом обеспечивается обратная совместимость и предоставляются механизмы для тех, кто может ими воспользоваться.
Здравствуйте, Vamp, Вы писали:
R>>Введение дополнительных функций конечно не является нарушением контракта, но и бессмысленно. R>>Интересно у кого раньше стек кончится...
V>Такое ощущение, что ты меня не слышишь. Попробую объяснить на очень простом примере. V>У тебя есть библиотека, вызывающая некоторое системное API. На момент разработки библиотеки API возврашало bool — success or failure. Соответствено, библиотечная функция тоже возвращала bool — предположим, собственных ошибок она породить не могла. В новой версии ОС API стало предоставлять дополнительные сведения об ошибках, и ты хочешь вернуть их пользователю. V>Расширять возвращаемое значение нельзя — посыпятся старые приложения. Единственный выход — ввести дополнительную функцию возврата расширеной ошибки. Таким образом обеспечивается обратная совместимость и предоставляются механизмы для тех, кто может ими воспользоваться.
Я тебя слышу, только ты говоришь о совершенно другой ситуации, когда мы можем менять контракт — твоя новая функция возврата расширенной ошибки — это новый контракт. В такой ситуации всё достаточно прозрачно и просто.
Я говорю о ситуации, когда контракт менять нельзя.
Допустим у меня есть моя реализация библиотеки pthreads, с расширенными функциями. Ты сейчас в своём приложении их используешь? Нет. Потому что тебе фиолетово на мой *новый* контракт, ты пишешь под POSIX. ДОпустим я тебе даю свою библиотеку. Тебе есть какая-то польза от этих расширенных функций? Нет. Потому что во-первы[, у тебя куча кода именно под POSIX, а во-вторых ты просто не хочешь затачивать свою программу под мой контракт, т.к. после этого под POSIX она даже компилироваться не будет.
Ну и что, имеет мне смысл менять контракт POSIX? Вот как хочешь, так под интерфейсом POSIX и пляши, даже если pthread_create() вызывает CreateThread(), которая может возвращать INVALID_SECURITY_DESCRIPTOR.
R>Допустим у меня есть моя реализация библиотеки pthreads, с расширенными функциями.
Ты пишешь не о контрактах, а о стандартах. Если твоя библиотека реализует некий СТАНДАРТ — то да, не убавить, ни прибавить. Но далеко не все контракты привязаны к стандартам. Кстати, даже в твоем примере, я не согласен.
ПОСИКС ориентирован на Nix. Если ты реализуешь кросслпатформенный посикс, умеющий работать в том числе под вин, то да, вполне можно ввести туда дополнительные функции типа get_win_error. В этом случае те, кому нужна чистая кроссплатформенность не будут ее использовать (а могут и использовать, если функция будет уметь закорачивать себя в иных средах), а те, кого интересует только виндовая имплементация — получат преимущества дополнительной диагностики.
Так что даже в твоем примере вполне полезно.
Здравствуйте, remark, Вы писали:
R>>>Там просто тупо давятся все ошибки.
ЮЖ>>Давятся, т.к. на уровне контракта в общем случае невозможно специфицировать все возможные ошибки, которые могут возникнуть в реализации.
R>Вот это я и пытаюсь решить.
Т.е. не только для отладочных целей? Можно аналог errno сделать, как в CRT(MSVC) добавили _doserrno.
errno value is not necessarily the same as the actual error code returned by a system call from the Windows operating systems. To access the actual operating system error code, use the _doserrno variable, which contains this value.
Здравствуйте, Vamp, Вы писали:
R>>Допустим у меня есть моя реализация библиотеки pthreads, с расширенными функциями.
V>Ты пишешь не о контрактах, а о стандартах.
А разница в данном контексте?
V>Если твоя библиотека реализует некий СТАНДАРТ — то да, не убавить, ни прибавить. Но далеко не все контракты привязаны к стандартам. Кстати, даже в твоем примере, я не согласен. V>ПОСИКС ориентирован на Nix. Если ты реализуешь кросслпатформенный посикс, умеющий работать в том числе под вин, то да, вполне можно ввести туда дополнительные функции типа get_win_error. В этом случае те, кому нужна чистая кроссплатформенность не будут ее использовать (а могут и использовать, если функция будет уметь закорачивать себя в иных средах), а те, кого интересует только виндовая имплементация — получат преимущества дополнительной диагностики. V>Так что даже в твоем примере вполне полезно.
Так а чего плохого предоставить какие-то преимущества и тем, кому нужна кросс-платформенность, если альтернатива только не предоставлять никаких преимущуств? Если речь о POSIX, то это — все пользователи. Писать под интерфейс POSIX, но при этом только под Windows, выглядит поменьшей мере странно.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
R>>>>Там просто тупо давятся все ошибки.
ЮЖ>>>Давятся, т.к. на уровне контракта в общем случае невозможно специфицировать все возможные ошибки, которые могут возникнуть в реализации.
R>>Вот это я и пытаюсь решить.
ЮЖ>Т.е. не только для отладочных целей?
Только для отладочных целей. Не для отладочных тут ничего не сделать, так пусть хоть будет для отладочных.
Можно аналог errno сделать, как в CRT(MSVC) добавили _doserrno.
R>Так а чего плохого предоставить какие-то преимущества и тем, кому нужна кросс-платформенность, если альтернатива только не предоставлять никаких преимущуств? Если речь о POSIX, то это — все пользователи. Писать под интерфейс POSIX, но при этом только под Windows, выглядит поменьшей мере странно.
Просто тем, кто пользуется позикс в юниксе, никаких преимуществ уже не нужно — подсистемане сможет верунть ничего такого, чтобы не было предусмотрено в позиксе.
Здравствуйте, Vamp, Вы писали:
R>>Так а чего плохого предоставить какие-то преимущества и тем, кому нужна кросс-платформенность, если альтернатива только не предоставлять никаких преимущуств? Если речь о POSIX, то это — все пользователи. Писать под интерфейс POSIX, но при этом только под Windows, выглядит поменьшей мере странно. V>Просто тем, кто пользуется позикс в юниксе, никаких преимуществ уже не нужно — подсистемане сможет верунть ничего такого, чтобы не было предусмотрено в позиксе.
R>Я рад за них. А остальным что делать?
Остальным — это кому? Тем, кто пользуется твоей библиотекой в средах, не реализующих позикс и предоставляющими дополнительние коды возврата — использовать get_ext_error.
Разве нет?
Здравствуйте, Vamp, Вы писали:
R>>Я рад за них. А остальным что делать?
V>Остальным — это кому? Тем, кто пользуется твоей библиотекой в средах, не реализующих позикс и предоставляющими дополнительние коды возврата — использовать get_ext_error. V>Разве нет?
Млять тем, кто просто пользуется интерфейсом POSIX. Не в средах, а просто. Что б работало и в Unix, и в Windows, и в MacOX.
Здравствуйте, Vamp, Вы писали:
R>>Млять тем, кто просто пользуется интерфейсом POSIX. Не в средах, а просто. Что б работало и в Unix, и в Windows, и в MacOX.
V>Разве мы не говорили о гипотетичском примере — кроссплатформенной реализации позикс? Я уже потерял нить.
Об этом и говорим. И у такой библиотеки могут быть не только пользователи, которые используют её под юникс, или которые используют её под виндовс. Могут быть и такие, которые используют её и под юникс и под виндовс, да ещё и не хотят отклоняться от интерфейса ПОСИКС.
Они не могут использовать get_ext_error(), но при этом им надо работать и под виндовс.
Вот представь себе. Реальная ситуация.
И это могут быть не только интерфейсы POSIX, но и ISO C/C++, или там какие-нибудь интерфейсы для XML.
R>Об этом и говорим. И у такой библиотеки могут быть не только пользователи, которые используют её под юникс, или которые используют её под виндовс. Могут быть и такие, которые используют её и под юникс и под виндовс, да ещё и не хотят отклоняться от интерфейса ПОСИКС.
Ради бога. Эти пользователи либо откажутся от использования get_ext_error, либо она всегда будет возвращать empty в не-вин средах.
R>Они не могут использовать get_ext_error(), но при этом им надо работать и под виндовс.
См. выше.
Здравствуйте, Vamp, Вы писали:
R>>Об этом и говорим. И у такой библиотеки могут быть не только пользователи, которые используют её под юникс, или которые используют её под виндовс. Могут быть и такие, которые используют её и под юникс и под виндовс, да ещё и не хотят отклоняться от интерфейса ПОСИКС. V>Ради бога. Эти пользователи либо откажутся от использования get_ext_error, либо она всегда будет возвращать empty в не-вин средах.
Я понимаю, что они откажутся. Они скорее всего даже и не будет рассматривать такую возможность. Вот об этом и речь, и что ты им предложишь?
С тем, что я предлагаю, им возможно будет чуточку полегче. По-крайней мере мне лично легче отлаживать — вся информация под рукой.
Здравствуйте, Vamp, Вы писали:
R>>Я понимаю, что они откажутся. Они скорее всего даже и не будет рассматривать такую возможность.
V>Не понимаю. Почему не будут рассматривать?
Не важно, забдуь. Пусть как ты сказал — они просто отказались. Так что ты можешь им предложить?
R>Не важно, забдуь. Пусть как ты сказал — они просто отказались. Так что ты можешь им предложить?
Переехать на Гоа например — и больше никогда ничего не программировать. Что значит "просто отказались"?
Здравствуйте, Vamp, Вы писали:
R>>Не важно, забдуь. Пусть как ты сказал — они просто отказались. Так что ты можешь им предложить? V>Переехать на Гоа например — и больше никогда ничего не программировать. Что значит "просто отказались"?
Честно говоря это уже смахивает на троллинг. Перечитай еще раз ветку, remark там все очень доходчиво объяснил.
Можно взять к примеру реализацию pthreads для win32 и на ее примере просто понять, почему нет смысла использовать расширенные функции, если есть необходимость потом написанное компилировать с настоящим pthreads.
W>Честно говоря это уже смахивает на троллинг.
Под кроватью у себя троллей поищи.
W>Можно взять к примеру реализацию pthreads для win32 и на ее примере просто понять, почему нет смысла использовать расширенные функции, если есть необходимость потом написанное компилировать с настоящим pthreads.
Вот я не понял. Объясни, если ты понимаешь.
Здравствуйте, Vamp, Вы писали:
W>>Честно говоря это уже смахивает на троллинг. V>Под кроватью у себя троллей поищи.
Ни к чему эта агрессия. Я вообще без эмоций писал.
W>>Можно взять к примеру реализацию pthreads для win32 и на ее примере просто понять, почему нет смысла использовать расширенные функции, если есть необходимость потом написанное компилировать с настоящим pthreads. V>Вот я не понял. Объясни, если ты понимаешь.
Я знаю как работать с pthreads, и не знаю этих расширенных функций. Это как минимум время на их изучение. Еще следует иметь в виду, что при компиляции с настоящими pthreads придется писать #ifdef #endif, чтобы расширенные функции не приводили к ошибке компиляции, потому что их там нет.
V>>Под кроватью у себя троллей поищи. W>Ни к чему эта агрессия. Я вообще без эмоций писал.
Я тоже без эмоций.
W>Я знаю как работать с pthreads, и не знаю этих расширенных функций. Это как минимум время на их изучение.
Ну новую библиотеку придется изучить, как ни крути. Это в любом случае так будет, даже с решением от Ремарка, потому что возвращаются коды ошибок неприменимые в юникс.
W>Еще следует иметь в виду, что при компиляции с настоящими pthreads придется писать #ifdef #endif, чтобы расширенные функции не приводили к ошибке компиляции, потому что их там нет.
Отчего же? Закорачиваться функции будут внутри библиотеки. Тебе ничего делать не надо.
Здравствуйте, Vamp, Вы писали:
V>Ну новую библиотеку придется изучить, как ни крути. Это в любом случае так будет, даже с решением от Ремарка, потому что возвращаются коды ошибок неприменимые в юникс.
Если мы говорим об эмуляции posix threads в win32, то коды должны быть одни и те же. Иначе это уже не эмуляция. И Ремарк писал, что контракт менять нельзя.
V>Отчего же? Закорачиваться функции будут внутри библиотеки. Тебе ничего делать не надо.
Пусть библиотека эмулятор преобразует коды текущей системы, в коды которые соответствуют контракту. А что делать с остальными?
W>Если мы говорим об эмуляции posix threads в win32, то коды должны быть одни и те же. Иначе это уже не эмуляция.
Мы говорим не о эмуляции, а о кроссплатформенной библиотеке, реализующий посикс.
W>И Ремарк писал, что контракт менять нельзя.
А я с ним спорил.
W>Пусть библиотека эмулятор преобразует коды текущей системы, в коды которые соответствуют контракту. А что делать с остальными?
Не путай библиотеку и эмулятор. Остальными кем?
Здравствуйте, Vamp, Вы писали:
W>>Если мы говорим об эмуляции posix threads в win32, то коды должны быть одни и те же. Иначе это уже не эмуляция. V>Мы говорим не о эмуляции, а о кроссплатформенной библиотеке, реализующий посикс.
Я тоже. У меня есть исходники написанные для c использованием pthreads, я хочу их скомпилировать под win32. Если такая библиотека будет предоставлять отличные коды ошибок (ты об этом сам выше написал) то тут тупо ничего не заработает.
Возможно слово неудачное — эмуляция. Я говорил о библиотеке, которая предоставляет интерфейс, идентичный pthreads. Эмулирует интерфейс. Но термин неудачный, ладно.
W>>Пусть библиотека эмулятор преобразует коды текущей системы, в коды которые соответствуют контракту. А что делать с остальными? V>Не путай библиотеку и эмулятор.
Я не путаю. Термин неудачный, двусмысленный.
V>Остальными кем?
Чем. Кодами. В данном случае системы win32. Кодами, которые не имеют эквивалента в posix.
Здравствуйте, Vamp, Вы писали:
W>>И Ремарк писал, что контракт менять нельзя. V>А я с ним спорил.
Я сам недавно с таким боролся. У меня был проект, который был написан на С++, юзалась библиотека XML, тоже на С++. Бибоиотека реализовывала модель SAX. Через наследование и определение виртуальных функций можно было задавать обработчики тэгов. В этих обработчиках активно использовались всякие исключения. Так как все было написано на С++ — проблем не было. Проблемы начались тогда, когда потребовалось сменить библиотеку XML c C++ на С. Был написан враппер, который повторял интерфейс той прежней библиотеки. Но встала проблема с исключениями. Исключения в данном случае нарушали контракт. Но старый код, а его очень много, трогать было слишком затратно. То есть решения переделать все на коды ошибок, или изменить архитектуру, что бы обрабатывать все исключения на одном уровне — уровне враппера не катили.
W>Я тоже. У меня есть исходники написанные для c использованием pthreads, я хочу их скомпилировать под win32. Если такая библиотека будет предоставлять отличные коды ошибок (ты об этом сам выше написал) то тут тупо ничего не заработает.
Разумеется. Именно по этому функции, определенные в позикс, будут возвращать коды ошибок, определенные в позикс.
W>Чем. Кодами. В данном случае системы win32. Кодами, которые не имеют эквивалента в posix.
Ну я об этом уже четыре часа пишу. Они будут возвращены через get_ext_error.
Здравствуйте, wander, Вы писали:
R>>>Не важно, забдуь. Пусть как ты сказал — они просто отказались. Так что ты можешь им предложить? V>>Переехать на Гоа например — и больше никогда ничего не программировать. Что значит "просто отказались"?
W>Честно говоря это уже смахивает на троллинг. Перечитай еще раз ветку, remark там все очень доходчиво объяснил. W>Можно взять к примеру реализацию pthreads для win32 и на ее примере просто понять, почему нет смысла использовать расширенные функции, если есть необходимость потом написанное компилировать с настоящим pthreads.
Ну слава богу, я уже начал думать, что это у меня крыша едет
Здравствуйте, Vamp, Вы писали:
V>Ну я об этом уже четыре часа пишу. Они будут возвращены через get_ext_error.
Ну мы опять вернулись на исходную позицию. То есть опять же мы переписываем исходники с использованием этой функции, вставляем ее в условную компиляцию, чтобы не мешалась под unix. Так?
W>Ну мы опять вернулись на исходную позицию. То есть опять же мы переписываем исходники с использованием этой функции, вставляем ее в условную компиляцию, чтобы не мешалась под unix. Так?
Нет, не так.
Мы добавляем вызов этой функции, если нас интересуют расширенные коды ошибок. Библиотека позаботится о том, чтобы она работала и в других средах.
Здравствуйте, Vamp, Вы писали:
V>Нет, не так. V>Мы добавляем вызов этой функции, если нас интересуют расширенные коды ошибок. Библиотека позаботится о том, чтобы она работала и в других средах.
Неверно. В другой среде будет не эта библиотека. А настоящий pthreads. Эта библиотека используется только в win32, чтобы дать возможность скомпилироваться юниксовым исходникам.
W>Неверно. В другой среде будет не эта библиотека. А настоящий pthreads. Эта библиотека используется только в win32, чтобы дать возможность скомпилироваться юниксовым исходникам.
А так работать не будет. Если у тебя в другой среде нет этой библиотеки, то include <pthreads_lib.h> отвалится с ошибкой. Или как?
А все-таки можно посмотреть кусок реального кода, где такое используется?
Просто я, например, до сих пор не применял такую мощную проверку ошибок (чтобы даже у CloseHandle ошибку проверять).
Дело не в самом unused<T>, хоть мне и показалось, что он против KISS, просто для меня непривычна такая плотность проверки ошибок, что даже приходится вводить специальные конструкции для этого.
Здравствуйте, SpaceConscience, Вы писали:
SC>А все-таки можно посмотреть кусок реального кода, где такое используется?
SC>Просто я, например, до сих пор не применял такую мощную проверку ошибок (чтобы даже у CloseHandle ошибку проверять).
SC>Дело не в самом unused<T>, хоть мне и показалось, что он против KISS, просто для меня непривычна такая плотность проверки ошибок, что даже приходится вводить специальные конструкции для этого.
Если бы это был С++, и поставлялось в исходных кода, то наверное тут бы пригодилось; а так это С89 и без исходных кодов, поэтому тут приходится по старинке.
RL_API int rl_thread_create(rl_thread_t* thr, rl_thread_start_t func, void* arg, rl_thread_prio_t prio, size_t stack_size)
{
rl_thread_impl_t* impl;
DWORD werr;
int err;
int win_prio;
if (thr == 0 || func == 0)
return RL_ERR_INVALID_ARG;
if (stack_size > UINT_MAX)
stack_size = UINT_MAX;
impl = (rl_thread_impl_t*)malloc(sizeof(rl_thread_impl_t));
if (impl == 0)
return RL_ERR_NOMEM;
thr->impl = impl;
impl->func = func;
impl->arg = arg;
impl->res = 0;
rl_atomic_size_store(&impl->rc, 2, rl_memory_order_nonatomic);
impl->handle = (HANDLE)_beginthreadex(0, (unsigned)stack_size, rl_thread_func, impl, 0, 0);
if (impl->handle == 0 || (uintptr_t)impl->handle == (uintptr_t)-1)
{
err = errno;
(void)err;
assert(!"failed to start a thread");
free(impl);
return RL_ERR_OTHER;
}
if (prio != rl_thread_prio_normal)
{
win_prio = THREAD_PRIORITY_NORMAL;
if (prio == rl_thread_prio_lowest)
win_prio = THREAD_PRIORITY_LOWEST;
else if (prio == rl_thread_prio_low)
win_prio = THREAD_PRIORITY_BELOW_NORMAL;
else if (prio == rl_thread_prio_high)
win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
else if (prio == rl_thread_prio_highest)
win_prio = THREAD_PRIORITY_HIGHEST;
if (0 == SetThreadPriority(impl->handle, win_prio))
{
werr = GetLastError();
(void)werr;
assert(!"failed to set thread's priority");
}
}
return 0;
}
RL_API int rl_thread_detach(rl_thread_t thr)
{
rl_thread_impl_t* impl;
DWORD err;
if (thr.impl == 0)
return RL_ERR_INVALID_ARG;
impl = (rl_thread_impl_t*)thr.impl;
if (FALSE == CloseHandle(impl->handle))
{
assert(!"failed to close thread's handle");
err = GetLastError();
(void)err;
return RL_ERR_OTHER;
}
if (1 == rl_atomic_size_fetch_sub(&impl->rc, 1, rl_memory_order_relaxed))
free(impl);
return 0;
}
Здравствуйте, SpaceConscience, Вы писали:
SC>Дело не в самом unused<T>, хоть мне и показалось, что он против KISS, просто для меня непривычна такая плотность проверки ошибок, что даже приходится вводить специальные конструкции для этого.
Специальные конструкции он вводит не для проверок ошибок (она и так присутствует), а в целях диагностики.
Пример в первом посте неудачный.
Здравствуйте, remark, Вы писали:
R>Если бы это был С++, и поставлялось в исходных кода, то наверное тут бы пригодилось; а так это С89 и без исходных кодов, поэтому тут приходится по старинке. R>
мое скромное мнение: все ассерты вырезать и убрать неиспользуемые переменные
библиотека пишется не для того, чтобы ее дебужили, а для того, чтобы ею пользовались
если моя программа будет выходить (exit) из-за какого-то ассерта в библиотеке, то я буду недоволен
а поставить бряку на return OTHER_ERR я всегда смогу при надобности
главное, что возвращается код ошибки ERR_OTHER, у клиента есть возможность анализировать ошибку
да, в этом коде недостаточно информации, но это общая беда ретурн кодов. при желании можно сразу проектировать более дескриптивные коды:
Здравствуйте, uzhas, Вы писали:
R>>Если бы это был С++, и поставлялось в исходных кода, то наверное тут бы пригодилось; а так это С89 и без исходных кодов, поэтому тут приходится по старинке. R>>
U>мое скромное мнение: все ассерты вырезать и убрать неиспользуемые переменные U>библиотека пишется не для того, чтобы ее дебужили, а для того, чтобы ею пользовались
Ну в начале-то её надо заставить работать. А потом постоянно убеждаться, что она не сломалась.
U>если моя программа будет выходить (exit) из-за какого-то ассерта в библиотеке, то я буду недоволен U>а поставить бряку на return OTHER_ERR я всегда смогу при надобности
Из-за ассёрта не вылетит, и бряку ты поставить не сможешь — поставляется релиз сборка без исходных кодов. Это всё для разработчика библиотеки.