Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.116.51.117] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Ограниченный массив отличается тем, что он защищён от выхода за границы. В данном случае как ограниченный массив должен вести себя класс. Что должен возвращать оператор []? Обычно он возвращает ссылку на элемент. Но если индекс выходит за границы массива, то элемента нет. Возвращать указатель не охота.
|
Сообщ.
#3
,
|
|
|
Так о несуществовании элемента будет знать только пользователь, но не вызывающй код. А должно быть наоборот. Вот представьте себе: элемент сам содержит массив, пользователь дал команду на удаление элемента члена элемента и не существующий индекс элемента, но существующий индекс элемента члена нулевого элемента, оператор [] написал, что элемент не существует, но прочитал это только пользователь, а в вызывающий код оператор [] вернул ссылку на нулевой элемент, вызывающий код получил эту ссылку и спокойно передал по ней члену нулевого элемента команду на удаление элемента, этот элемент удалился, а в нём был не сохранённый результат пары часов редактирования. Резервировать нулевой элемент как заглушку несущесвующего и на этом успокоиться тоже нельзя. Иначе пользователь введёт информацию и туда. И её может быть много. Если пользователю надо знать, что он сделал что-то не то, то сообщить об этом должен не оператор, а вызывающий код. Хотя бы потому, что вызывающий код «знает», куда пользователь ввёл не существующий индекс. Индекс, кстати, строковый, а не числовой, так что сравнить в вызывающем коде значение индекса с количеством элементов нельзя.
Добавлено Цитата JoeUser @ Куда? В ветвь оконной процедуры? И как потом продолжить нормальную работу гуя? Ладно, не велика сложность. Для одного раза. Но ловить исклюкаку придётся по всей приладе, а это уже повод для максимального упрощения. Трай им не страдает. А по-моему лучше кидать исключение. |
Сообщ.
#4
,
|
|
|
Цитата Ирокез @ Куда? В ветвь оконной процедуры? Кидают не куда, а где. А "куда" - это где обрабатывают. Простой пример, понятный и удобный; #include <iostream> using namespace std; class MyArray10 { public: MyArray10() : a{'0','1','2','3','4','5','6','7','8','9'} {}; char &operator[](size_t idx) { if (idx>9) throw std::out_of_range("MyArray10"); return a[idx]; } private: char a[10]; }; int main() { MyArray10 Arr; try { std::cout << std::hex << Arr[1] << std::endl; std::cout << std::hex << Arr[10] << std::endl; } catch (std::out_of_range &e) { std::cout << "Выход за границы массива в: " << e.what() << std::endl; } catch (...) { std::cout << "Произошла неведомая хрень" << std::endl; } return 0; } Добавлено Цитата Ирокез @ И как потом продолжить нормальную работу гуя? Не сложнее, если ты будешь отлавливать предварительно условными операторами. |
Сообщ.
#5
,
|
|
|
Хотелось бы без неё, пусть даже переусложнив одно место. А если уж делать через неё, то какую именно исклюкаку принято бросать? Я попробовал
throw *this Добавлено Цитата JoeUser @ Ну где – это в операторе. Кидают не куда |
Сообщ.
#6
,
|
|
|
Цитата Ирокез @ то какую именно исклюкаку принято бросать Я в примере ее привел - std::out_of_range Добавлено Если хочется еще и this знать - нужно реализовать свой класс исключения, наследовавшись от std::out_of_range. Добавлено Хотя ... можно и адрес передавать при выбросе исключения: #include <iostream> using namespace std; template<typename S,typename D> D type_cast(S s) { union Tmp { S src; D dst; } T; T.src = s; return T.dst; } class MyArray10 { public: MyArray10() : a{'0','1','2','3','4','5','6','7','8','9'} {}; char &operator[](size_t idx) { if (idx>9) throw std::out_of_range(type_cast<MyArray10*,char*>(this)); return a[idx]; } private: char a[10]; }; int main() { MyArray10 Arr; try { std::cout << std::hex << Arr[1] << std::endl; std::cout << std::hex << Arr[10] << std::endl; } catch (std::out_of_range &e) { std::cout << "Выход за границы массива в: " << std::hex << static_cast <const void *> (e.what()) << std::endl; } catch (...) { std::cout << "Произошла неведомая хрень" << std::endl; } return 0; } |
Сообщ.
#7
,
|
|
|
Цитата JoeUser @ Что я с ним делать буду? Объект хоть тип имеет, по нему можно понять, оператор-член какого класса бросал. А адрес я куда приткну? Хотя ... можно и адрес передавать при выбросе исключения: |
Сообщ.
#8
,
|
|
|
Цитата Ирокез @ Что я с ним делать буду? Без понятия. Это был ответ на ваш вопрос #5. Вы в исключении передавали this и у вас программа падала. Я показал как передать, чтобы не падала, и как это адрес в обработчике достать. Хотите более детальной обработки, творите. Default решений тут нет. Цитата Ирокез @ Объект хоть тип имеет, по нему можно понять, оператор-член какого класса бросал Откройте для себя RTTI, хотя бы почитайте про std::type_info. |
Сообщ.
#9
,
|
|
|
Цитата JoeUser @ Учитесь читать. Я передал ссылку на this. Вы в исключении передавали this Добавлено Цитата JoeUser @ Вот только она разбирает фактические типы объектов, а не адреса кода. Откройте для себя RTTI, |
Сообщ.
#10
,
|
|
|
Цитата Ирокез @ Учитесь читать. Я передал ссылку на this. И результат - падение программы. Я это читал. Добавлено Цитата Ирокез @ Объект хоть тип имеет, по нему можно понять, оператор-член какого класса бросал Цитата Ирокез @ Вот только она разбирает фактические типы объектов, а не адреса кода. Сначала же надо было знать тип?! Или, по мере обсуждения, цели меняются? |
Сообщ.
#11
,
|
|
|
Цитата JoeUser @ Не читал, а выхватил. И результат - падение программы. Я это читал. Добавлено Цитата JoeUser @ Да. Но Вы-то предлагали адрес операции, на которой исклюкака брошена. Сначала же надо было знать тип?! Добавлено Цитата JoeUser @ Не цели, а средства. Цель – узнать, чем вызвана исклюкака. Или, по мере обсуждения, цели меняются? |
Сообщ.
#12
,
|
|
|
В последнем моем варианте в исключении прилетает адрес экземпляра класса, в операторе которого произошло исключение. Тип этого экземпляра класса узнать можно. Если нужно еще что-то, это нужно реализовывать самостоятельно. В отличии от языков с динамической типизацией, в С++ из подобного только RTII со своими фишками. Но нет преграды патриотам.
Добавлено Цитата Ирокез @ Вы-то предлагали адрес операции, на которой исклюкака брошена Адрес точно операции? |
Сообщ.
#13
,
|
|
|
Цитата JoeUser @ А чего? Места жительства Меркель? Адрес точно операции? Добавлено Цитата JoeUser @ Чтоб по адресу узнать фактический тип, его надо запихать в указатель на базовый класс. А что это за класс? В последнем моем варианте в исключении прилетает адрес экземпляра класса, в операторе которого произошло исключение. Тип этого экземпляра класса узнать можно. Если нужно еще что-то, это нужно реализовывать самостоятельно. Добавлено Цитата JoeUser @ В c++ размещаемые в куче экзмлпяры полиморфных классов получают фактические типы вполне динамически. В отличии от языков с динамической типизацией, |
Сообщ.
#14
,
|
|
|
Цитата JoeUser @ Лучше? Только исключение. Никаких вариантов. А по-моему лучше кидать исключение. Добавлено Цитата Ирокез @ Нагрузить экземпляр исключения любой информацией никто не мешает. Какая там будет нужна информация, кроме автора кода, знать некому, так что "пилите Шура, пилите"©, компилятор сам по наитию этого не сделает Что я с ним делать буду? Объект хоть тип имеет, по нему можно понять, оператор-член какого класса бросал. А адрес я куда приткну? |
Сообщ.
#15
,
|
|
|
Цитата Ирокез @ Чтоб по адресу узнать фактический тип, его надо запихать в указатель на базовый класс. А что это за класс? Ну я же давал ссылку на доки. Что и так почитать лень? Хотите узнать название класса? В доке и пример есть: #include <iostream> #include <typeinfo> struct Base { virtual ~Base() = default; }; struct Derived : Base {}; int main() { Base b1; Derived d1; const Base *pb = &b1; std::cout << typeid(*pb).name() << '\n'; pb = &d1; std::cout << typeid(*pb).name() << '\n'; } Добавлено Цитата Qraizer @ Лучше? Только исключение. Никаких вариантов. Да, тамошний пример от интуристов, что я приводил, в плане работы с ошибками - хрень. Согласен. |