1. Пользуйтесь тегами кода. - [code] ... [/code] 2. Точно указывайте язык, название и версию компилятора (интерпретатора). 3. Название темы должно быть информативным. В описании темы указываем язык!!!
Скачал я себе ГНАТ (Gnat GPL(без исходников, поленился все ссылки тыкать) и Win32Ada. Скопировал я для начала в редактор кода текст из Википедии:
with Ada.Text_IO;
procedure Hello is use Ada.Text_IO; begin Put_Line("Hello, world!"); end Hello.
Нажимаю "проверка синтаксиса".
[2011-01-18 21:32:02] Could not determine the project for file: C:\ADA\projects\Test\test.gpr [2011-01-18 21:32:02] Invalid context, cannot build
В общем, я так понял, я пока с какими-то настройками не разобрался, что делать? Заметил, что можно копировать сообщения об ошибках в буфер обмена. Ещё, что функцию можно свернуть. После каждого сворачивания/разворачивания в конец добавляется пустая строчка (баг, есть таблетка?). В настройках цвета не нашёл отдельного цвета для символов. Мне нравится, когда скобочки и запятые коричневые, а не чёрные.
иногда в шаблоне надо инициализировать переменную неопределённого типа хоть чем-то.
Пишется функция, возвращающая определенное значение для определенного типа, и передается в пакет при инстанцировании.
Цитата
Тут можно использовать анонимные процедурные типы в заголовке функции?!
Более того, только подобное описание будет работать при любом раскладе. Если ты предварительно опишешь тип, а потом будешь его использовать в заголовке (дельфийская практика), то даже если это и заработает где-то в одном случае, всегда остается вероятность, что в других случаях это работать не будет. Конкретный пример приводил C. Okasaki, но найти его сейчас у меня не получилось...
Цитата
Ещё, по аналогии с Unbounded_String, нету ли в стандарте шаблонного Unbounded_Array для любого типа?
Вообще-то в стандарте и Ada.Containers.Ordered_Maps и Ada.Containers.Hashed_Maps есть, это ж тебя не останавливает от написания своего Dictionary?
> Если ты предварительно опишешь тип, а потом будешь его использовать в заголовке (дельфийская практика), то даже если это и заработает где-то в одном случае, всегда остается вероятность, что в других случаях это работать не будет.
Тогда зачем вообще может понадобиться описывать такой тип? Так, вспомнил. При описании оконного класса (в задании оконной функции) проблем тут не будет?
> Вообще-то в стандарте и Ada.Containers.Ordered_Maps и Ada.Containers.Hashed_Maps есть, это ж тебя не останавливает от написания своего Dictionary?
Словарь я пишу свой, потому что: 1. Велосипеды полезны для общего развития и особенно для изучения языка. 2. Я пишу именно префиксное дерево (а не красно-чёрное дерево (Ordered_Maps) и не хеш-список (Hashed_Maps)) даже не для хранения данных по ключу (хотя у него очень высокая алгоритмическая эффективность), а для выделения самого длинного слова словаря, являющегося началом данной строки (или продолжением строки с определённой позиции). То есть это именно словарь, а не карта.
В Дельфи меня парило, что этот словарь надо самому удалять, у меня даже были мысли делать его динмассивом, а вместо ссылок использловать номера потомков в массиве. Народ ещё рассказывал про хитрые приведения к интерфейсам (для автоудаления), я, правда, не знаю, насколько это обезопасит от мёртвых ссылок. Ну и ещё (в Д7) я для универсальности (шаблонов-то нету) брал словарь строк из строк, а другие типы побайтово отображал в строку.
При описании оконного класса (в задании оконной функции) проблем тут не будет?
Нет, не будет. Вот это, кстати, тот случай, когда описание отдельного типа необходимо: смена соглашения о вызове. Для отдельно описанного типа Func_Type это делается
Посмотрел я Container.Vector. Не нашёл двух функций (самых главных, наверное). Array_To_Vector и Vector_To_Array Поэлементно собирать неудобно. И в доступе к элементу много проверок. Компилятор умеет ветки, состоящие только из выброса исключения, распознавать как проверки и выкидывать в неотладочной версии?
Новая проблема. Я обнаружил утечку памяти у себя. Стал искать. Нашёл.
Суть такая. Есть процедура P(T: out aInteger); Где-то внутри неё происходит T := new integer; И где-то дальше (внутри неё) какая-то проверка на корректность выражения и выброс исключения. Внешний код примерно такой:
PF.T := null; P(PF.T); что-то сделать с PF.T
И в деструкторе объекта PF прописано что-то типа if T /= null then Free(T);
Так вот, если внутри P кинуть исключение, то значение переменной PF.T, передаваемой внутрь процедуры, останется старым (как будто её не трогали)! И к объекту, созданному внутри, нет доступа и он повиснет в памяти - утечка. То есть сопоставления внутренного out-параметра и внешней переменной как бы и нету, оно неявно копируется при корректном выходе из процедуры, а при некорректном внутренний объект висит. Что делать?
Так вот, если внутри P кинуть исключение, то значение переменной PF.T, передаваемой внутрь процедуры, останется старым
Во-первых, внутрь процедуры ничего не передается. out параметр - это ожидание, что процедура заполнит и передаст назад какое-то значение. Так что даже если ты инициализируешь чем-то PF.T перед тем, как вызвать процедуру, при выбросе исключения в PF.T все равно будет null. А во-вторых, такое поведение компилятора прописано в Стандарте языка:
Цитата(Ada RM 6.4.1)
After normal completion and leaving of a subprogram, for each in out or out parameter that is passed by copy, the value of the formal parameter is converted to the subtype of the variable given as the actual parameter and assigned to it. These conversions and assignments occur in an arbitrary order.
Согласно пункту 6.2 ссылочный тип - это тип, передающийся "by copy", а выброс исключения не может считаться "нормальным завершением программы"
Вывод: не передавать через out-параметры ссылочных (или любых других передающихся "by copy" типов), если подпрограмма может выбросить исключение. Как WorkAround (в твоем случае) - ловить в той же процедуре свое же исключение, освобождать память, и raise-ом отправлять дальше...
P.S. Отделил от темы кусок, связанный с поиском утечек, в отдельную тему...
Ну допустим, в моём случае, я разберусь как-то, что в случае исключения надо освободить память, как-то разберусь в этой вложенной рекурсивной структуре, где что надо освобождать в случае утечки. Но если мне дейтвительно снаружи нужно значение указателя (или целого) даже если выкинулось исключение? Есть ли оператор, который позволил бы прямо записать в наружные параметры результат? Аналогичный вопрос про return (и все языки, где он есть) - как одновременно выкинуть исключение и вернуть значение?
А вообще мысль с копированием переменной в стек хорошая - меньше неявных разыменований указателя, оптимизация...
По-моему, у кого-то неправильное понимание сущности исключений...
Цитата
Ada Model of Exceptions
<...> To raise an exception is to abandon normal program execution thus drawing attention to the fact that the corresponding situation has arisen.
<...> When an exception occurrence is raised by the execution of a given construct, the rest of the execution of that construct is abandoned; that is, any portions of the execution that have not yet taken place are not performed.
Поскольку возврат функцией результата - это завершающее действие (равно как и возврат out-параметров), и если ты хочешь исключение, ты должен его выбросить раньше, то ни функция ни процедура не завершат работу нормально, это будет исключительная ситуация, и текущая конструкция не выполнится. То есть, в Аде это технически невозможно. Не пользуются исключениями одновременно с возвратом значения. Либо одно, либо другое.
Максимум, что можно предложить - это в случае исключения забрасывать результат в глобальную переменную... Но это неверный дизайн.
Да я вообще исключениями впервые в жизни решил воспользоваться. Обычно всё на кодах возврата пишу, а исключениями просто обматываю некоторые куски после жалоб пользователей, чтобы если упадёт, то пользователю вывелось что-нибудь посодержательнее, чем "облом по адресу 87654321, обращение к 12345678".
У меня почему-то стало пропадать окно с переменными. То есть если его открыть, потом отрубить отладчик, а потом снова запустить отладчик, то окна переменных не будет видно, чтобы оно появилось, надо все окна утащить в сторону (как плавающие). В режиме отладки вместо строк, передаваемых в процедуры, видны какие-то адреса, при попытке узнать, что по ним, показывает "неизвестная переменная". Вычисление функций в режиме отладки не работает. Пока пытаюсь понять, почему моя программа показывает окно только в неотладочном режиме, а в отладочном не хочет регистрировать оконных класс.
Добавлено через 13 мин. Переменная для extended return не видна в отладчике.
Вот тут я записал небольшое видео, прекрасно показывается окно переменных при инициализации/финализации дебаггера... И окно создается в режиме Debug. И строку показывает...
Цитата
Переменная для extended return не видна в отладчике.
И это неправда. Поменял процедуру на функцию, и вот:
Может, все дело - в том, что у тебя Gnat GPL 2010, а у меня - GPL 2009? Все-таки, в 2010 они вводили какие-то фичи из стандарта 2012, может, поломали чего?
Для того, чтобы преобразовать строку в PCCH при создании оконного класса, я применял функцию, создававшую временный контролируемый объект, который внутри хранил выделенную в куче строку S&0, а также поле с указателем на эту строку. В финализаторе объекта эта строка удалялась. Если написать что-то типа
Ещё проблема. Большую часть времени написания код я не код пишу, а проблемы такие пытаюсь разгребать. Очень тяжело, просто ужас как тяжело. Если бы ботланд не додумался до идиотской идеи не вводить автодеструкторы в ООП, я бы давно забил на ГНАТ.
Не знаю, мне не с чем сравнивать. Я 2010 под Windows не видел никогда. 2009 - совершенно нормальная версия. Пока не примут А2012, и не поправят под него компилятор - дома обновляться не собираюсь.