Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.200.66] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
У всех языков свои особенности. Нельзя даже сказать что достоинства или недостатки. Где-то достоинства, а где-то недостатки.
У C++ одна из основных ключевых фишек это итераторы. Везде и всегда итераторы. Ими можно осуществлять ввод, вывод, перебор, перестановку, перемещение, копирование, заполнение и так далее. Даже указать позицию для вставки или элемент для удаления. У C# его енумераторы, как-бы предоставляют базовую функциональность итераторов, но труба пониже, а дым пожиже. Можно перечислить коллекцию. Можно даже что-то сэмитировать. Но этого мало. А в итоге приходится огород городить. С другой же стороны в C# чуть иная объектная модель. Например, ту же задачу для C# я бы решил передав объект абстрактного типа TextWriter. А там уже пофиг какой именно объект StreamWriter, StringWriter или иное чудо-юдо. Но это корректно именно в C#. А для C++ просто так поток не передать. Ну, тоесть можно передать ссылку, а внутри хранить указатель на std::ostream. Раньше, кстати, именно так и делал, но такой код выглядит неестественным. Да уж, если говорить прямо, то старомодным. Использование чистых небезопасных указателей, это весьма рискованный ход повышающий шанс отстрелить себе ногу. К тому же это создаёт искуственные ограничения. А ведь до чего же удобно, записать текст прямо в строку, не дёргая потоки. У php и видимо большинства скриптовых языков, дела с итераторами и перечислениями обстоят ещё хуже. Ну что это за ботва, когда енумератор скрыт в самом контейнере? Да, на простых задачках это удобно и даже в чём-то упрощает жизнь. А что делать если надо два или три перечислителя? Тогда же приходится совсем жутко извращаться, доходя даже до полного дублирования самого контейнера. С другой же стороны, у скриптовых языков, проблемы типизации объектов, не стоят так остро и можно юзать трюки, которые в плюсах доступны лишь через шаблоны. Кстати, я внедоумении от файловых потоков в C++. Они, помоему, слишком ретроградны. Используют тоже один или два курсора, вместо итератора. А ведь эти потоки, можно и даже нужно рассматривать, как полноценные контейнеры вроде std::vector или std::list. Это позволило бы упростить алгоритмы и унифицировать внутренние сущности. Единственное что их оправдывает, так это обратная совместимость и традиционность. А касательно концептов, так их обещались добавить в C++17. Так что жду и недождусь. http://zouev.blogspot.ru/2009/07/blog-post_09.html Я же не имея возможности воспользоватся автогенератором кода, был вынужден написать примерно то, как представляю механизм реализованный под копотом концептов. Это выглядит чудовищно... Но всё же, хоть так. А ведь в принципе, думаю, что это позволит, например в скомпилированную библиотеку направлять итераторы. Поскольку обёртка инстанцируется на стороне клиента, а реализация на стороне обработчика. Хорошо бы конечно добавить всякие самопроверки, чтоб выскакивали внятные ошибки, мол в указанном типе не реализован оператор * или =. А то этот код, вполне реально загнать в логический тупик с жуткой простынёй ошибок и предупреждений. Эта тема была разделена из темы "как передать произвольный итератор в скомпилированный класс?" |
Сообщ.
#2
,
|
|
|
Видя такой код, я все больше и больше испытываю, мягко говоря, "уныние" от ЯП со статической типизацией. И все эти уверения "да это же помощь программисту!" сродни украинским СМИ
Что мы имеет по сути? Есть некоторая функция, которая берет на вход контейнер (ну не контейнер, а его части, отдаваемые итератором) и функциональный объект, производит обработку. И все. А сколько усилий для преодоления "помощи программисту" Цитата Eric-S @ Ну что это за ботва, когда енумератор скрыт в самом контейнере? Да, на простых задачках это удобно и даже в чём-то упрощает жизнь. А что делать если надо два или три перечислителя? Вот нельзя так огульно за все языки говорить. Возьму и добавлю свой Энумератор. Более того, есть возможность с помощью метатаблиц переоперделить оператор [], но это уже другая тема, тут не буду. Пример на Lua: -- инициализация ----------------------------------- Array = {1,2," три ",4,5," шесть ",7,8,9} -- свойство таблицы -------------------------------- function Array:EnumeratorEven(Idx) return Idx*2 > #self and nil or Idx*2 end -- печать таблицы по определенному свойству ------- function PrintEven(Container) local I,R = 0,'' repeat I = I + 1 local T = Array[Array:EnumeratorEven(I)] if T then R = R .. T else break end until (false) print("Res: " .. R) end -- точка начала исполнения ------------------------- PrintEven(Array) Я понимаю, код не Бог весть какой, но мне простительно - изучаю Lua только один день. Внезапно понадобилось. А вот теперь представим сколько тонн шаблонов из STL потянет! А тут - просто свойства и особенности языка. ЗЫ: Lua - второе "откровение" после Руби, в целом "просто отлично"! |
Сообщ.
#3
,
|
|
|
Цитата JoeUser @ Видя такой код, я все больше и больше испытываю, мягко говоря, "уныние" от ЯП со статической типизацией. И все эти уверения "да это же помощь программисту!" сродни украинским СМИ Э, нет. Дело не в статической типизации. А в компиляции в машинный код. Я бы обошёлся бы без всего этого, если бы сделал функцию шаблонной. То есть, хоп, функция шаблонная, и мне обёртка нафиг не нужна. Только я захотел нешаблонную функцию, а значит поехали приключения. Что же касается интерпретируемых языков, то они ведь все шаблонные по определению. Далее, если бы у всех классов, был бы единый базовый класс, да ещё бы в стандартной библиотеки имелись огромные коллекции интерфейсов на все случии жизни, причём всё и всегда передавалось бы по указателю, то вопрос опять бы не стоял. Конечно, это всё можно сделать. Но стоить будет слишком дорого. Банальная виртуализация зачастую избыточна. А значит от неё можно и нужно избавиться.Пусть будет опциональной, лишь для тех кому она нужна. Объекты в динамической памяти излишняя роскошь. Мелочь можно хранить на стеке. А значит динамическая память только опционально, когда она действительно нужна. В итоге имеем, то что имеем. Для высокого уровня скрипты, хотя бы тот же ruby или lua. Кстати, lua действительно интересный. А для низкого уровня другие языки с иными принципами, для решения других задачь. Везде есть свои плюсы и минусы. Конечно, C++ уже морально устарел. У него много недостатков, а развитие слишком медленное. Но именно C++ позволяет мне делать всякие вкусняшки, которые труднодостижимы в интерпретируемых языках. При всей своей крутизне, даже сайтостроители, отказываются от интерпретаторов, в пользу C и C++. У других языков, вроде D или Rust тоже есть свои вкусняшки. Но они в погоне за плюшками, потеряли этакую своеобразную наивную чистоту C++. |
Сообщ.
#4
,
|
|
|
Цитата Eric-S @ Но именно C++ позволяет мне делать всякие вкусняшки, которые труднодостижимы в интерпретируемых языках. Слабо верится Можно пример? |
Сообщ.
#5
,
|
|
|
Цитата JoeUser @ Слабо верится Можно пример? Ну например частотный анализ звукового сигнала в реальном времени. Или даже банальная склейка фонем, опять же в реальном времени. Чтобы были бинарные буфера, которые поочереди подсовываются звуковухе для заполнения, а затем шерстятся несколькими алгоритмами вдоль и поперёк, определяя спектры частот, делают слепки, сравнивая их с базой данных, загруженной в память... А вот сейчас модернезирую обработку текста с распознанием внутренних лексических сущностей и моделированием разнообразных взаимодействий. Интерпретаторы от такого кошмарика ложатся из-за банальной нехватки памяти и быстродействия. Пробовал набрасывать отдельные элементы. Так разница по скорости обработки в тысячу раз. Ради интереса попробовал сделать загрузку и декодирование файлов на ruby... и озадачился кодировками. Почему-то не придумалось, как добавить парочку велосипедов. Да и хитрые алгоритмы поиска слов, не слишком удобно делать. Я лишь прикинул и решил, что не взлетит. Впринципе языки вроде rust, java, c# дают уже неплохую скорость. Но в них, труднее выразить некоторые абстракции, которые на C++ делаю банальным множественным наследованием. То есть языки с одиночным наследованием, ограничивают код по выразительности. Ах да, и конечно же, C++ позволяет мне обернуть вызов любой системной функции, с минимальными накладными расходами. Когда я написал словарь на C# (словарь в смысле базу данных специализированную для хранения и выборки слов), то очень огорчился низкой скоростью. На C++ этот же словарь (частично доделаный) работает гораздо быстрее. Ну да там ещё дело в конвертации типов данных и в маршализации. На C++ оно тоже получается быстрее и проще. А уж до чего прикольный конвертор получился на шаблонах... Я когда пытался повторить его на C# почти рыдал от невозможности прогнуть язык под свои хотелки. |
Сообщ.
#6
,
|
|
|
Цитата Eric-S @ Интерпретаторы от такого кошмарика ложатся из-за банальной нехватки памяти и быстродействия. Пробовал набрасывать отдельные элементы. Так разница по скорости обработки в тысячу раз. Остается верить на слово На каком интерпретируемом ЯП ты это пробовал? |
Сообщ.
#7
,
|
|
|
Ты прав. В холиварах этому диалогу самое место.
Цитата JoeUser @ Остается верить на слово На каком интерпретируемом ЯП ты это пробовал? Глупо верить любым голословным утверждениям, даже моим. Ради справедливости, надо переписать и протестировать идентичный функционал. Тогда получатся более реальные тайминги. Я начинал на C#. Попробовал перенести на php, но почти сразу бросил, обнаружив тормоза и уперевшись в доступный объём памяти. php брал как единственный известный мне кросплатформенный язык, способный из коробки открывать и писать файлы. За образец функционала, точнее за идею, брал код спелчекера на nodejs и морфера на python. Они делали нечто похожее, но с функциональными ограничениями. Откровенно говоря, подходы и опирации различались. То есть функционал далеко неоднозначный. Суть алгоритма объяснять долго, поскольку некоторые моменты не выкрестолизовались в моей голове. Там много мелких нюансов. Возможно ещё буду приставать к народу по этому поводу. Но если упрощать, то одну из задач, можно свести к постраению графа сырых слов. В точке само слово. А связи соединяют его с похожими словами. Сырые слова, в том смысле, что выдернутые прямо из текста, без какой либо морфологической и прочей обработки. Сравнивать надо всё со всем и чем больше слов, тем лучше. В конечном результате, программа, чисто эврестически должна создать словарь слов проставив каждому слову оценку его корректности. Там много всякого накручено, так что для более-менее адекватной синтетической замены, можно попробовать забацать классическую пузырьковую сортировку строк на огромном массиве. |
Сообщ.
#8
,
|
|
|
Вообще читая всякие тесты когда один язык сравнивается с другим, я каждый раз замечал, что тестировщик либо пишет неоптимальный код, либо какой-то язык из коробки приспособлен лучше для решения конкретной задачи, чем другой.
Так что в идеале, надо сравнивать примеры кода, написанные упоротыми фанатиками конкретного языка. Но тогда опять же алгоритмы будут различатся, затрудняя сравнения. А ещё смущают некоторые вставки... Например php-разработчик вызывает функцию написанную на C. И приэтом считает себя выйгравшим. Мол php быстрее чем C. |
Сообщ.
#9
,
|
|
|
Цитата Eric-S @ Там много всякого накручено, так что для более-менее адекватной синтетической замены, можно попробовать забацать классическую пузырьковую сортировку строк на огромном массиве. Ну давай сравним С тебя реализация на С++ исполняемого файла. Постановка задачи простая: 1) Прочитать из текстового файла, заданного как аргумент командной строки, текст 2) Разбить на слова, разделителями слов являются: пробел, знак табуляции, перевод строки, возврат каретки 3) Вывести в STDOUT все найденные слова в порядке убывания частот, в формате слово : число_посторений А я все тоже самое сделаю на Perl, Ruby, Lua - и запущу для теста на своей машине, результаты отпищу тут. Для теста попробую собрать "эталоны" текстовых файлов в 100Мb, 500Mb, 1Gb, 4Gb Договорились? Добавлено Цитата Eric-S @ Например php-разработчик вызывает функцию написанную на C. И приэтом считает себя выйгравшим. Имеет право Ты же на C++ используешь API ОС, не пишешь свои драйвера? Почему бы мне не пользоваться, к примеру, на том же Perl'е модулем, который юзает чужую динамическую либу, которая позволит мне перенести часть вычислений на GPU, просто, чтобы перегнать тебя и "наказать за самоуверенность" |
Сообщ.
#10
,
|
|
|
Цитата JoeUser @ Договорились? Ох... И не лень? Блин... Уже начал продумывать, как это дело заоптимизировать обходными трюками. Вот ведь маньяк. Не, это дело плохо пахнет. Но так можно дойти и до использования стандартных функций и контейнеров. Ладно... Я подумаю ещё. Может и напишу. Шибко оно похоже на "а тебе слабо?" От такого я бегу как от огня. Тем более стрёмно отстаивать честь C++, словно я самый крайний. А вообще, надобы обговорить условия. Что можно использовать, а чего нельзя. Очень хочется предложить повозможности использовать язык, а не его стандартную библиотеку. Но тут же возникает ощущение, что собираюсь обидеть ребёнка. Цитата JoeUser @ Почему бы мне не пользоваться, к примеру, на том же Perl'е модулем, который юзает чужую динамическую либу, которая позволит мне перенести часть вычислений на GPU, просто, чтобы перегнать тебя и "наказать за самоуверенность" Эх... Вот тут и вылизают недостатки синтетических тестов. А зачем тогда вообще чего-то писать, если есть стандартные утилиты? Вот ты предлагаешь выборку слова, определив конкретные разделители. Угу, тут всё просто, дёргаем функцию split или чего-нибудь вроде неё. Но результат будет синтетический и нафиг ненужный. Тоесть сам тест окажется притянутым зауши. А как насчёт выборки реальных слов из реального текста? Там, где эти разделители хрен знает что. И уже хотя бы поэтому, стандартную функцию нельзя дёрнуть, а придётся писать свою функцию. Именно свою, поскольку в стандартных либах такой функции нет. Ну вот например знак '-' может разделять слова, а может быть внутри них. Знак точки может быть внутри слова, а может быть в конце предложения. А как насчёт реального корректного сравнения слов? С учётом спецефичных особенностей? Слова надо раставить без учёта регистра, без учёта преффиксных и суффиксных символов и даже считая, но не ломая букву 'ё'? Тут ведь подвох в самой задаче. Потому я и говорю, что мне ненравятся синтетические тесты. И сама задача надуманная. И условия подбираются так, чтоб компьютеру их было проще решить. Я ведь не олемпиадник. И некоторые вещи из принципа делаю определённым образом. Например читаю и пишу файл потоками std::ifstream, std::ofstream. А тут, при постановке задачи, так и напрашивается открыть файл через CreateFilе. Я обычно использую стандартное выделение памяти, через vector или make_shared... Но тут так и хочется заюзать VirtualAlloc. То есть решение-то сильное, но далеко не жизненное. И да, хочу заметить, что в большинстве известных мне интерпретаторов, включая и интерпретаторы байткода, используют спецефические менеджеры памяти. То есть будет очень даже справедливо, если я заюзаю тоже спецефический менеджер памяти. |
Сообщ.
#11
,
|
|
|
Цитата Eric-S @ А как насчёт реального корректного сравнения слов? С учётом спецефичных особенностей? Слова надо раставить без учёта регистра, без учёта преффиксных и суффиксных символов и даже считая, но не ломая букву 'ё'? В том-то и дело ... не нужно городить мозговыносный тест, что-то простое ... как сам сказал, без никаких либ, чисто инструментами языка. Вот сам посуди. Пока ты размышлял о кораблях, бороздящих просторы тестов ... я собственно тест (тупо влоб) написал: #!/usr/bin/perl open (FD,$ARGV[0]) || die "Shit!"; map {$Freq{$_}++;} split /\s+/, join "", <FD>; close (FD); map {print $_." : ".$Freq{$_}."\n";} sort {$Freq{$b}<=>$Freq{$a}} keys %Freq; Оптимизаций нуль. Но на малых текстах - твое время написания кода на С++, да плюс его выполнение - будут медленнее. Уже медленее. Улавливаешь суть? Добавлено Цитата Eric-S @ Но тут так и хочется заюзать VirtualAlloc На больших файлах - надо mmap, имхо. И по скорости, и по гемору - меньше. |
Сообщ.
#12
,
|
|
|
Цитата JoeUser @ Вот сам посуди. Пока ты размышлял о кораблях, бороздящих просторы тестов ... я собственно тест (тупо влоб) написал: Вообще-то мне тупо лень сейчас чего-то писать. Зато есть огромное желание защитить результат от жульнечества. Если уж тестить, то результат должен быть максимально объективным. Добавлено Цитата JoeUser @ Но на малых текстах - твое время написания кода на С++, да плюс его выполнение - будут медленнее. Это естественно. Как я писал ранее, задачи у языков разные. Добавлено Цитата JoeUser @ На больших файлах - надо mmap, имхо. И по скорости, и по гемору - меньше. Может быть и так, но я эту тему вообще не колупал. |
Сообщ.
#13
,
|
|
|
Цитата Eric-S @ Если уж тестить, то результат должен быть максимально объективным. Ну пока то у тя и защищать-то нечего) Добавлено Цитата Eric-S @ Может быть и так, но я эту тему вообще не колупал. Да тут все просто как грабли - управление чтением и размещением данных в страницах памяти ты отдаешь на откуп операционной системе ... а "не учишь её как ей правильно жить" |
Сообщ.
#14
,
|
|
|
Цитата JoeUser @ Пока ты размышлял о кораблях, бороздящих просторы тестов ... я собственно тест (тупо влоб) написал: #!/usr/bin/perl open (FD,$ARGV[0]) || die "Shit!"; map {$Freq{$_}++;} split /\s+/, join "", <FD>; close (FD); map {print $_." : ".$Freq{$_}."\n";} sort {$Freq{$b}<=>$Freq{$a}} keys %Freq; Оптимизаций нуль. Но на малых текстах - твое время написания кода на С++, да плюс его выполнение - будут медленнее. Ну тупо в лоб и на C++ примерно так же: ifstream f(argv[0]); string word; unordered_map<string, size_t> dict; while (f >> word) ++dict[word]; vector<pair<string, int> > res; res.reserve(dict.size()); copy(dict.begin(), dict.end(), back_inserter(res)); sort(res.begin(), res.end(), [](const auto & a, const auto & b) {return a.second > b.second;}); for (auto & w_c : res) cout << w_c.first << " : " << w_c.second << endl; Не? Код не проверял, если что |
Сообщ.
#15
,
|
|
|
Цитата D_KEY @ Код не проверял, если что Норм код Цитата D_KEY @ Не? Ну а если по-честноку, то: #include <unordered_map> #include <algorithm> #include <iostream> #include <sstream> #include <vector> using namespace std; int main() { stringstream f("Мама мыла мыла раму"); string word; unordered_map<string, size_t> dict; while (f >> word) ++dict[word]; vector<pair<string, int> > res; res.reserve(dict.size()); copy(dict.begin(), dict.end(), back_inserter(res)); sort(res.begin(), res.end(), [](const auto & a, const auto & b) {return a.second > b.second;}); for (auto & w_c : res) cout << w_c.first << " : " << w_c.second << endl; return 0; } Т.е. +заголовки, +main, и +необработанный fstream. И это еще не все ... Это +подтягивание STL-а ... А этого не хотел Eric-S, типа "давай без либ!". Я все исполнил честно ЗЫ: Если с либами - заходим на http://www.cpan.org/ и выбираем модуль из которого будем писать программу в одну строчку Ну или почти ... |