OSDev

для всех
Текущее время: 02 июл 2025, 02:14

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 15, 16, 17, 18, 19, 20, 21 ... 29  След.
Автор Сообщение
СообщениеДобавлено: 01 янв 2015, 16:15 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
Хорошо, это как раз показывает разницу, которую получим, если пытаться избавиться от ассемблера. В моём заказе на Int128 было требование обойтись без ассемблера.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 янв 2015, 03:09 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 976
Откуда: Дагоба
Zealint писал(а):
Отступы могут оказаться неправильными по той же ошибке. Мы думаем, что во внутреннем блоке, а уже давно во внешнем, или наоборот. Эту ошибку я наблюдал у школьников, которых раньше учил. Язык, как мне кажется, должен быть понятен и им тоже.

Если человек учится кататься на роликах, он неизбежно падает. А профессионалы практически не падают. Людям в теории понятно, как нужно кататься, но на практике нужно немного практики, чтобы всё было как в теории. Извиняюсь за невольный каламбур.

Zealint писал(а):
Классический цикл for из Си можно оставить таким, какой он есть. Можно придумывать разные причины, по которым он неудобен, но вот, например, наиболее простой (из читаемых) способ развернуть массив в обратном порядке
Код:
int a [ N ];
...
for ( int i = 0, j = N – 1; i < j; i ++, j -- )
   swap ( a [ i ], a [ j ] );

Я не знаю, каким способом это можно было бы сделать более изящно без подобного цикла for.

Всё больше прихожу к выводу, что подобные циклы for хоть и уменьшают количество строк кода, но затуманивают суть. Вот эта пачка операторов в скобках неудобоварима. Думаю, вот этот код хоть и длинней (только по количеству строк), но понятен с первого взгляда:
Код:
int a[N];
...
int i = 0;
int j = N–1;
while i<j {
  swap (a[i], a[j]);
  i++;
  j--;
}

В остальном по циклам согласен.

Zealint писал(а):
В качестве альтернативного варианта определения типов можно заставить определять их как локальные переменные:
Код:
void f ( a, b, c, d ) {
  int a, d;
  double b, d;
  ...
}

Ведь эти переменные всё равно будут локальными.

Какие же они локальные, если вызывающей функции нужно 1) подготовить соответствующие параметры и 2) выбрать нужный вариант из кучи перегруженных функций?

Zealint писал(а):
В-третьих, вместо функций иногда приходится создавать функторы, то есть классы, в которых переопределена операция «круглые скобки», чтобы смотреть на функцию как на класс. Зачем? Не только для того, чтобы можно было передавать её в качестве аргумента (для этого можно использовать указатель на функции), но и для того, чтобы можно было пользоваться деструктором. Бывает, что возникает следующая неприятная ситуация:
Код:
  ...

Явное дублирование кода. Данная проблема, конечно, решается с помощью goto и переменной, сохраняющей результат. Но ещё удобнее затолкать освобождение памяти в деструктор, и когда функтор уничтожается, вся память нормально освобождается. Не нужно перегружать тело функции обслуживающими операциями. Однако беда в том, что процедуры выделения памяти всё равно приходится прописывать в теле функции. Было бы удобно сочинить способ, в результате которого служебные процедуры в начале и в конце функции прописывались где-нибудь не в её теле.

Я думаю, что подобная ситуация решается exit-блоком, т.е. таким блоком, который всегда выполняется перед выходом из функции.

Zealint писал(а):
А если ещё и дать возможность делать такие штуки:
Код:
void f ( . . . , int a, . . ., double b ) {
  ...
}

То есть дать программисту возможность сказать, что где-то «в середине» один из параметров должен быть int, а последний должен быть double, то мы даём разработчику компилятора задачу, возиться с которой ему будет не проще, чем с любой труднорешаемой задачей. Компилятор станет экспоненциальным по сложности, даже если не добавлять возможность указать значение параметров по умолчанию.

По этой причине оператор "многоточие" стоит разрешить только в конце списка аргументов, как это сделано сейчас.

Zealint писал(а):
Далее. Программист должен управлять возможностью делать функцию встроенной (inline) или нет (notinline). Эти требования должны быть не рекомендацией компилятору, а жёстким требованием...

Почему?

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 янв 2015, 05:46 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1449
Zealint писал(а):
Программист должен управлять возможностью делать функцию встроенной (inline) или нет (notinline). Эти требования должны быть не рекомендацией компилятору, а жёстким требованием

А почему не предусмотреть возможность и жёсткого варианта, и мягкого?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 янв 2015, 16:04 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 976
Откуда: Дагоба
В своё время умные изобретатели почесали свои натруженные головы и в помощь слабосильным компиляторам решили добавить ключевое слово "register". Однако, очень скоро стало ясно, что компилятору видней, что стоит размещать в регистрах, а что - нет. Теперь это слово если и не под запретом, то по крайней мере не рекомендуется к употреблению, т.к. может помешать компилятору разместить переменные оптимальным способом. Чувствую я, что у "inline" та же судьба. Я бы вообще отказался от этого ключевого слова и предоставил бы компилятору возможность самостоятельно решать, что подставлять в код, а что оставлять в виде функции.
Я думаю так: задача исходных текстов - максимально просто и корректно описать логику алгоритма. А задача компилятора - максимально эффективным способом отобразить эту логику на целевую архитектуру. Ключевые слова "register" и "inline" - это (неудачная) попытка влезть не в свою сферу компетенции.

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 янв 2015, 19:49 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
Yoda писал(а):
Какие же они локальные, если вызывающей функции нужно 1) подготовить соответствующие параметры и 2) выбрать нужный вариант из кучи перегруженных функций?

Да, это я фигню сказал, если функция определена в другой единице трансляции, то непонятно, как подготовить вызов. Если функция определена в том же файле, то всё путём, но так бывает далеко не всегда.

Yoda писал(а):
Я думаю, что подобная ситуация решается exit-блоком, т.е. таким блоком, который всегда выполняется перед выходом из функции.

Ну так я про то же. Нужен механизм, который позволяет определить этот exit-блок. Если он определён, то обязательно вызывается при корректном выходе из функции. Сейчас пользуются деструктором вместо такого exit-блока.

Yoda писал(а):
Цитата:
Далее. Программист должен управлять возможностью делать функцию встроенной (inline) или нет (notinline). Эти требования должны быть не рекомендацией компилятору, а жёстким требованием...

Почему?

Когда я это написал, то думал, что мне это ключевое слово не нравится именно потому, что непонятно, будет ли на самом деле функция встроенной или нет. Особенно неясно как быть, когда функция-член класса определена в заголовочном файле, а её тело - в файле с реализацией. Негоже это - тело прописывать в заголовочном файле. Поэтому данное ключевое слово (inline) призвано заставить компилятор каким-то образом "достать" тело функции из другого файла, если он может его правильно найти. Поэтому если уж и делать такое ключевое слово, то жёстко требовать от него исполнения своего назначения. Если же запретить это слово совсем, то действительно всем будет лучше. Что касается notinline, то особого смысла в нём нет, просто странным кажется, что делать функцию встроенной можно, а невстроенной - нельзя.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 06 янв 2015, 20:01 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1449
Zealint писал(а):
Нужен механизм, который позволяет определить этот exit-блок. Если он определён, то обязательно вызывается при корректном выходе из функции


В Дельфях весьма полезны блоки try-finally, ну а возможность их вкладывания, а также смешивания с try-except добавляет гибкости.

Цитата:
Если же запретить это слово совсем, то действительно всем будет лучше


Не всем и не всегда. Человеку зачастую лучше знать, как функции используются, и явное указание желательности встраивания может помочь принять компилятору решение (или обязать его встроить -- как я уже сказал, лучше иметь возможность и приказывать, и советовать).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 15 янв 2015, 20:22 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
[ 20 ] :: Классы

Уверен, что у каждого свои обоснованные представления о том, какими должны быть классы. Вот, например, взять наследование. Каким оно должно быть? Занимаясь «научным» программированием, мне вообще не приходилось им пользоваться ни разу. Занимаясь промышленным программированием, к наследованию приходилось прибегать довольно часто. Однако даже там private и protected наследования мне ни разу не попадались. Могу ли я из этого сделать далеко идущие выводы об их бесполезности? Нет. Для этого нужны данные и большой опыт работы в области разработки ПО.

В высокоуровневом программировании (в моих задачах) классы используются не на полную мощность и всего лишь как удобство для некоторой рутинной работы и возможность избежать дублирования разных конструкций. Там главная задача – оптимизировать лишь 10-20% кода, а остальное лишь бы просто работало.

В разработке ПО же главным является простота и безопасность конструкций. Поэтому инкапсуляция, например, играет важную роль в безопасности, полиморфизм и наследование позволяют упростить код. Хотя, конечно, можно по-разному смотреть на эти вещи. Нужны ли они в HPC, я не знаю. Нужно ли следовать в HPC тем же принципам, что используются в разработке ПО, я тоже не знаю. Раньше я, например, вообще обходился только функциями и в редких случаях структурами для объединения переменных в одну группу. Такие вещи, как сокрытие данных вообще не имели смысла, потому что я никогда не делал ошибок, типичных для разработки ПО, не только в силу опыта, но и потому что для подобных ошибок просто не было почвы. Я не мог ошибиться и испортить значения по неконстантной ссылке или попортить член класса, обращаясь к нему напрямую, а не через функцию типа get / set, у меня не было необходимости дублировать код, потому что объектов с похожими свойствами в программе просто не возникало, а ошибок, связанных с тем, что «здесь исправил а тут забыл» не могло быть в принципе, потому что неудачная в чём-либо программа не исправлялась, а безжалостно удалялась, чтобы можно было написать новую без соблазна скопировать ошибочную (в плане идеи, а не реализации) конструкцию. А вот с разработкой ПО всё сложнее. Там, наоборот, думать надо о простоте и безопасности, барахтаясь в болоте рутины и примитивных одинаковых конструкций. Случайно ошибиться в силу объёма кода может даже профессионал выше моего уровня (и обязательно сделает это), поэтому всякие императивы ООП нужны ему в достаточной мере.

Возможно, в HCP всё-таки нужны не только программы, решающие конкретные задачи, но и полноценное ПО, поэтому язык должен поддерживать стандартные элементы ООП, однако поскольку я их использовал на практике редко, высказаться о классах могу лишь отчасти.

Собирая свой небольшой опыт работы с классами в кучу могу сказать следующее. Мне кажется, что все данные классов всегда должны быть скрыты, обратиться к ним можно только через функции.

Далее, нужен способ обращения к внутренним данным класса, который не порождал бы конфликтов имён. Например, наиболее частая проблема:
Код:
class Star {
public:
   Star ( int x_, int y_ ) : x(x_), y(y_) { }
private:
   int x, y;
};

Если кого-то совершенно не раздражает описанная в этом примере проблема, то я могу только порадоваться за него, но лично мне такие люди не встречались. В нормальном языке такого быть не должно. Не знаю, как вы, но я прямо-таки чувствую в этой проблеме типичную недоработку проектирования. Казалось бы, выходом могло бы стать создание пространства имён над всеми переменными, но вот ведь незадача! - нельзя делать пространство имён внутри класса. Класс внутри класса тоже не вариант, думаю, не надо пояснять, почему.

Порадовало, что появились ключевые слова override и final. Что-то похожее должно быть обязательно.

Также радует, что можно теперь запретить функции, которые компилятор создаёт по умолчанию (помечать их как «delete»). Такая штуковина тоже полезна. По крайней мере, если я хочу запретить создавать объект конструктором по умолчанию, мне теперь не нужно прятать его в private-область (тело-то для него всё равно нужно определять).

Далее, при наследовании нужно учесть возможность переопределять НЕ все виртуальные функции. Если я по какой-то причине не хочу переопределять функцию из базового класса, я не обязан это делать. Не знаю как сейчас, но раньше это было ошибкой, когда такие функции остались без тела. Вообще, мне кажется полезным сообщать об ошибке, связанной с отсутствием тела функции, только тогда, когда это тело действительно нужно, то есть откуда-то вызывается.

Несколько удручала меня раньше проблема, при которой я не мог вызвать конструктор с параметром для массива объектов одного класса. Как-то так:
Код:
Star * stars = new Star [ 10 ] ( 5, 6 ) // Создать 10 звёзд с координатами (5,6).

Или, что было бы ещё чудеснее:
Код:
/* Создать 10 звёзд с координатами (0,0), (1,1) и т. д. */
Star * stars = new Star [ 10 ] ( [] ( int index ) -> (int, int) { return (index, index); } )

Разумеется, я вовсе не настаиваю на подобном синтаксисе. Я лишь хочу сказать, что при создании массива объектов иногда хочется использовать конструктор с параметрами для каждого объекта. Правда же я не один такой требовательный?

Иногда требуется создать одну и ту же функцию-член в двух экземплярах: константную и неконстантную:
Код:
const int & operator [ ] ( int index ) const { return data [ index ]; }
int & operator [ ] ( int index ) { return data [ index ]; } 

Нет разницы между этими функциями. Но делать их нужно две и хоть ты тресни. А бывает, что тело функции имеет несколько больший размер и налицо явное дублирование кода. Можно извратиться и сделать всё через макросы, но куда удобнее писать на языке без применения костылей.

Иногда нужна серия функций типа get/set, для управления скрытыми переменными. Мне кажется, в большинстве случаев их можно как-то автоматически генерировать.

Нужны ли какие-то специальные виды классов для особого применения (типа синглотонов, делегатов и т. д.), я тоже не знаю. В C++ эти штуки вполне делаются штатными методами.

И последнее, то есть не самое главное. С точки зрения полного понимания идеи сокрытия данных нельзя прописывать названия переменных внутри объявления класса в заголовочном файле. Однако вынести эти переменные в другой файл без лишних довольно существенных телодвижений тоже нельзя. От этого тоже веет какой-то недоработкой.

Каких-то особенных нестандартных идей по классам у меня сейчас нет.

[ Продолжение следует ]


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 15 янв 2015, 21:19 

Зарегистрирован: 28 окт 2007, 18:33
Сообщения: 1449
Zealint писал(а):
Иногда нужна серия функций типа get/set, для управления скрытыми переменными. Мне кажется, в большинстве случаев их можно как-то автоматически генерировать


В Дельфях свойства видели? Как по мне, самое то.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 15 янв 2015, 22:05 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
SII писал(а):
В Дельфях свойства видели? Как по мне, самое то.

Всё-таки не совсем. Там всё равно нужно прописывать эти функции. А хочется чтобы они сами появились в виде реализации по умолчанию, но при условии, что пользователь не определил их сам. Например,

Код:
class Star {
...
private:
  int x, y;
};
...
Star S;
// Все 4 функции ниже пользователь НЕ прописывает нигде, они сразу есть.
int x = S . getx ( );
int y = S . gety ( );
S . setx ( x + 1 );
S . sety ( y + 1 );


Конечно, можно было бы ещё подумать над названиями таких функций, ведь необязательно согласовывать их с названиями переменных, которые должны быть скрыты. В этом смысле давать им названия можно было бы как в Delphi, но чтобы реализация по умолчанию генерировалась сама.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 15 янв 2015, 22:11 
Аватара пользователя

Зарегистрирован: 16 май 2007, 23:46
Сообщения: 1126
А Delphi с этим нет проблем это не java.
Код:
  TByteMap=class
  private
    FP:Pointer;
    FMap:Pointer;
    FLineLen:Integer;
    ...
  public
    property LineLen: Integer read FLineLen;
    ...
 end;

Код:
Bm:=TBitmap.Create;
LL:=bp.LineLen;

И не надо Get Set писать.
А если хочется то в дельфи есть автогенератор кода для классов. Буквально в один клик мыши она сама создает get и set по умолчанию.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 15, 16, 17, 18, 19, 20, 21 ... 29  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB