Здравствуйте, Tilir, Вы писали:
T>Дело в том, что throw попадает под return.
Неа. Warning пропадает, если возвращать значение (не ссылку).
T>Забавный кстати случай поскольку throw index имеет вообще-то тип void. И почему компилятор вообще разрешает return condition ? int : void -- загадка.
Ага! Вот из стандарта:
5.16.2 If either the second or the third operand has type (possibly cv-qualified) void, then the lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed on the second and third operands, and one of the following shall hold:
— The second or the third operand (but not both) is a throw-expression; the result is of the type of the other and is an rvalue.
И зачем так сделали? Или это не относится к моему вопросу?
Если не поможет, будем действовать током... 600 Вольт (C)
-MyXa-:
MX>5.16.2 If either the second or the third operand has type (possibly cv-qualified) void, then the lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed on the second and third operands, and one of the following shall hold:
MX>— The second or the third operand (but not both) is a throw-expression; the result is of the type of the other and is an rvalue.
MX>И зачем так сделали?
Я бы тоже хотел узнать ответ на этот вопрос В стандарте даже не сказано, каким образом должно получаться это rvalue (возможные варианты: это может быть либо гарантированно исходный объект, либо copy-initialized temporary object, либо copy constructed temporary object).
MX>Или это не относится к моему вопросу?
Относится. Компилятор считает, что ты пытаешься вернуть по ссылке временный объект, который по выходе из функции существовать не будет.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, -MyXa-, Вы писали:
E>Почему сказали, но не понятно, зачем писать так кудряво-то?
А сам что сделал? Теперь к тернарному оператору ещё и запятая прибавилась, и фиктивное обращение к элементу тож...
ИМХО лучше отделить бросок от возврата
template<typename T>
T const & at(T const * const a, std::size_t const index, std::size_t const size)
{
if(index<0||index>=count)
throw std::range_error( MAKE_ERROR_MESSAGE("index %d out of range [0,%d)", index,count) );
return a[index];
}
И кстати! Бросаться целыми числами — дурной тон.
Хотя бы потому, что при catch нас ждут сюрпризы с совпадением-несовпадением формального типа.
Здравствуйте, Кодт, Вы писали:
E>>Почему сказали, но не понятно, зачем писать так кудряво-то?
К>А сам что сделал? Теперь к тернарному оператору ещё и запятая прибавилась, и фиктивное обращение к элементу тож...
Дык это если таки хочется кудряво
Кудряво-то тоже можно. Просто не нужно...
К>ИМХО лучше отделить бросок от возврата
Конечно лучше.
К>И кстати! Бросаться целыми числами — дурной тон. К>Хотя бы потому, что при catch нас ждут сюрпризы с совпадением-несовпадением формального типа.
Ну это отдельный вопрос. Кстати, а разве с целыми именно ждут сюрпризы? Хотя при бросании всяких разных типов надо помнить, что преобразования там таки почти не делаются...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
К>>И кстати! Бросаться целыми числами — дурной тон. К>>Хотя бы потому, что при catch нас ждут сюрпризы с совпадением-несовпадением формального типа.
E>Ну это отдельный вопрос. Кстати, а разве с целыми именно ждут сюрпризы? Хотя при бросании всяких разных типов надо помнить, что преобразования там таки почти не делаются...
Вообще, неподконтрольное множество используемых типов исключений — это бардак. Но с числами это особенно больно и обидно.
Для классов действует сопоставление с супертипом = базовым классом, что логично.
А для чисел нет супертипа, хотя это и не интуитивно. При выборе сигнатуры функции компилятор делает неявное преобразование (потому что компилятор умный!), а при выборе сигнатуры catch — не делает (потому что это уже не компилятор, а глупый рантайм).
В результате, бросая size_t, нужно ловить именно size_t, а не unsigned long или unsigned int.
Это даёт возможности для ряда ошибок:
— случайный перехват (например, одна функция кидает index, а другая — hresult; если тип индекса совпадёт с HRESULT, будет внезапно)
— случайное игнорирование (например, все функции кидают index, но у большинства это int, а у нескольких пуристов size_t и ptrdiff_t)
— случайный бросок неподходящего типа (например, все кидают char, но в одном месте было throw('Z'), а в другом — throw('A'+25), продвинутый до int)
Ну и для рефакторинга это мучительно. В специально обученный тип исключения всегда можно подверстать дополнительную информацию, да и выявить все точки использования этого типа в программе (хотя бы тупым поиском). А тип общего назначения, да ещё и широко используемый и неявно выводимый — беда.
К>Ну и для рефакторинга это мучительно. В специально обученный тип исключения всегда можно подверстать дополнительную информацию, да и выявить все точки использования этого типа в программе (хотя бы тупым поиском). А тип общего назначения, да ещё и широко используемый и неявно выводимый — беда.
Ага. И именно по этому, наш статический анализатор Viva64, входящий в состав PVS-Studio имеет диагностику ошибок связанных с использованием memsize типов в исключениях при переходе на 64-битные системы. Подробнее см. описание диагностических сообщений V115 и V116.