LINUX.ORG.RU

Rust и двусвязный список

 , двусвязный список,


4

2

Хорошую тему тут затронули

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

http://contain-rs.github.io/linked-list/src/linked_list/lib.rs.html#11-1388

Или не лучшее? Растаманы и растафобы, собирайтесь на великую битву!

А вот, кстати, ещё про списки:

https://rust-unofficial.github.io/too-many-lists/

★★★★★

Последнее исправление: den73 (всего исправлений: 1)

Ответ на: комментарий от khrundel

Ты задачу ставишь неправильно. Граф – слишком дорогая и сложная структура данных, чтобы делать её на все случаи жизни. Реализация графа обычно делается под задачу. Если traversal, то – одно, pattern matching – другое. Статичный граф – еще варианты, динамический – варианты. Нужно упихнуть как можно больше в оперативную память – варианты. В память GPU – варианты.

Если же просто какой-то универсальный граф, то это обычно «список ребер» (так абстрактная организация данных называется). Как уже этот «список» реализовать – отдельная задача. Обычно это не просто список, а multimap.

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

vector<_> ты бенчмаркал неправильно. Вставка в конец O(1) у него амортизированная, что значит, что на N операций O(1) будет одна операция О(N) (худший случай). Тогда как у списков худший случай – O(1). По этой причине, например, большие сетевые кэши делают на деревьях, а не на hashmap. Чтобы SLA по задержкам выдерживать, когда хэш-таблица решит себя пересобрать (очень редко, но очень долго).

aist1 ★★★
()
Ответ на: комментарий от khrundel

В моём бенчмарке обрабатывалось как раз самое сложное для массива - реаллокация при росте.

в своем «бенчмарке» ты сравнивал время аллокирования N байт на хипменеджере, с временем сдвига M байт в памяти. Такое сравнивать конечно можно…но смысла большого в этом нет.

список это упорядоченное множество произвольных элементов, а массив это N элементов ОДНОГО типа, лежащих друг за другом… которые тоже выражают собой казалось бы «упорядоченное множество», НО это вовсе не так.

при рандомной вставке/удалении(а мы расматриваем только такую вставку) в список, все указатели на другие элементы остаются валидными. при рандомной вставке/удалении в массив индексы последующих элементов становятся невалидными(из за сдвига). то есть не все алгоритмы, работающие на списках, могут быть отображены на массивы.

также список хорош тем, что не имеет ограничений по длине. массив имеет.

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от den73

ну это довольно просто - количество взаимосвязей, которые нужно учитывать в компиляторе, велико и будет расти со временем

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

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

Аналогично. Ну и редакции как раз позволяют выкидывать фичи. Плюс так проще собирать статистику: ты можешь посмотреть сколько (опенсурсных) библиотек какой редакции есть и на основе этого делать вывод когда можно будет убрать поддержку самой старой. С набором разрозненных фич так сложнее. К слову, для раста что-то подобное уже делают: все библиотеки с crates.io собираются новыми версиями чтобы проверить отсутствие регрессий.

Плюс из-за наличия старого кода не будут достигнуты какие-то целевые показатели.

И в очередной раз: ты похоже пропустил контекст. У тебя с языком есть примерно три варианта: никогда не ломать обратную совместимость и обрастать кривостями, постоянно всё ломать и распугать разработчиков и наконец пытаться аккуратно помечать фичи устаревшими и убирать их через какое-то время.

DarkEld3r ★★★★★
()
Ответ на: комментарий от eao197

А Mozilla среди разработчиков известная компания была, так что буст хайпу обеспечить смогла

Спорить не буду. Но я бы всё-таки разделял (агрессивный) маркетинг и действительно безальтернативное пропихивание.

DarkEld3r ★★★★★
()
Ответ на: комментарий от den73

Также не хватает размещения на стеке массивов переменного размера, как в C99.

Ты ведь знаешь, что в С11 их «убрали»? Вернее, сделали не обязательными. Не смущает?

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

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

Совершенно обойдена вниманием тема конвертации. Допустим, что 4-й вариант поведения компилятора «держать фичи вечно, но самостоятельно сконвертировать исходник из прошлой редакции языка в нынешнюю, оставив семантику полностью той же» выглядит дико, но все же как насчет точной конвертации по запросу программиста?

a--
()
Последнее исправление: a-- (всего исправлений: 2)
Ответ на: комментарий от den73

Мрак, как сказала бы Эллочка-людоедка.

В С++ тоже есть стандарты.

C++98, C++11, C++14, C++17, C++20, C++23.

И фичи какие-то добавляются, какие-то выкидываются.

И можно собирать одно приложение из разных объектных файлов собранных разными стандартами.

Без понятия почему в расте используется эпохи, и некоторые говорят что в С++ нужны эпохи, когда отличий от стандарта нет никаких.

fsb4000 ★★★★★
()
Ответ на: комментарий от khrundel

будешь искать место для вставки/удаления

А что, нет вариантов найти запись, кроме как проитерироват весь список? Ах, ну да у вас же руст, там так нельзя, лул.

crutch_master ★★★★★
()
Ответ на: комментарий от crutch_master

Да, связанные структуры практически непригодны для итерирования. Что ставит крест на осмысленности их применения.

Потому что ты так решил? Если кому-то не надо их итерировать целиком? Если ты так не делаешь, у тебя нет таких задач, это не значит что их ни у никого нет.

Ты бы определился всё-таки, как ты собрался списком побеждать массив. Что ты планируешь делать?

Да я не собираюсь списком побеждать массив. Это ты религиозный воен, а я использую удобные для задачи структуры там, где они уместны.

Каждый из этих вариантов я уже рассмотрел

Рассмотрел самые удобные для себя варианты, молодец, адепт. А неудобные не рассматривал? Нарезку списка на кусочки не рассмотрел? Пересборку списка из этих кусочков не рассмотрел? Вставку списка в середину списка? Про всякие закольцованные структуры - я вообще молчу. У тебя же кроме массива ничего нет, значит и возможности думать про такое тоже нет. Религия запрещает - значит не нужно. А единственное, что можно делать со структурой - это дрочить её быстро-быстро итератором от начала до конца.

crutch_master ★★★★★
()
Ответ на: комментарий от khrundel

нода в графе может быть вообще недостижима ниоткуда.

В таком случае её нужно грохнуть.

Либо достижима по нескольким путям

Тогда в чём проблема?

Как ты собрался перечислять эти ноды?

Зачем их перечислять? Чтобы что?

Хочешь - не хочешь, тебе придётся заводить общий контейнер содержащий все ноды графа, т.е. дополнительный список либо массив.

Если он тебе нужен. Ты подминаешь реальность под свои ограниченные взгляды.

Больше не пригодились.

Если не пригодилась лично *тебе* это не значит, что это никогда и никому не будет нужно. _Не_ значит. Запомни это пожалуйста.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 2)
Ответ на: комментарий от khrundel

Не поверишь - если ты попытаешься подобное со списком творить, то тебе потребуется этот какой-то по счёту элемент найти.

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

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от a--

а по моей ссылке 6к слов с осмысленным содержанием

Поинт в том, что я дал ссылку на официальный design guide и там про метапрограммирование ничего. Откуда можно сделать вывод и статусе поддержки этой фичи.

Вы разыскали пропозал, судьба которого неизвестна. Может быть в итоге будет так, как написано в пропозале. А может и нет.

eao197 ★★★★★
()
Ответ на: комментарий от khrundel

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

Тайм-ауты одинаковые, что дает возможность просто добавлять новые таймеры в конец списка, без поиска подходящего места вставки.

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

Двусвязный список здесь отлично работает.

Итерироваться по нему вообще никогда не приходится. Для отмены таймера используется некий ID, который может быть просто указателем на элемент списка. Поэтому при отмене таймера мы всегда точно знаем какой именно элемент нужно изъять.

При этом наш список автоматически адаптируется под нагрузку: будь в нем хоть 100 элементов, хоть 100000 элементов, лишнюю память он не занимает и объем занятой памяти сам собой растет и уменьшается в зависимости от количества активных таймеров. Используй мы вектора вместо списка пришлось бы эту проблему решать дополнительно.

Ну и я не буду утверждать, что подобное нельзя замутить на векторах. Все возможно. Вопрос только зачем?

eao197 ★★★★★
()
Ответ на: комментарий от alysnix

в своем «бенчмарке» ты сравнивал время аллокирования N байт на хипменеджере, с временем сдвига M байт в памяти. Такое сравнивать конечно можно…но смысла большого в этом нет.

Как нет? В реальном коде у тебя будет какой-то другой, волшебный аллокатор, который тебе всё мгновенно заполнит? Или ты недовольным пользователям будешь предъявлять результат профайлера и говорить, что ты за тормоза внутри malloc ответственности не несёшь? Или ты какой-то иной смысл в бенчмарки вкладываешь, не проверить как оно работает, а продемонстрировать гениальную идею?

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

при рандомной вставке/удалении(а мы расматриваем только такую вставку) в список, все указатели на другие элементы остаются валидными. при рандомной вставке/удалении в массив индексы последующих элементов становятся невалидными(из за сдвига)

Чё, серьёзно что ли? Вот так прямо рандомная вставка и валидные указатели?

Давай ты попытаешься думать по-человечески. Не «как мне оправдать использование списка», а «как решить задачу наиболее эффективно». Возьмём как исходную точку массив. Тебе нужно зачем-то хранить разные элементы в нём, но предположим. Что делаем? Правильно, массив указателей. Заодно получаем неумирающие внешние ссылки. Однако нам нужно пробегать по массиву и искать что-то, а обращаться по указателю - это плохо. Давай поменяем тип айтемов на указатель + ключ для поиска, чтоб удобнее искать, без косвенной адресации. И ещё сделаем эффективное удаление, т.е. добавим поддержку пустых ячеек. Ничего полученная конструкция не напоминает? Ё-моё, так это ж половина хэш-таблицы с открытой адресацией, можно не колхозить, а заюзать её. Да, условие упорядоченности не выполняется, но тут такой момент: список в принципе не пригоден для прохода его по-порядку, так что твоё «упорядоченный» не имеет практического значения.

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

на самом то деле большинство нормального софта сделано с использованием списков.

Большинство - точно нет, потому что нормальный софт пишут не студенты-первокурсники. Но много где используется, да. Но это не значит что реально нужно.

пример - оконный менеджер - окна провязаны в списки

Может так, а может и нет, ты ведь просто пальцем в небо ткнул. В любом случае, это плохой пример. Сколько этих окон? 10? 50? Там можно в чём угодно хранить и как угодно обрабатывать.

геймдев - всякие там физ обьекты,

Чего не знаю, того не знаю, может где-то и используются. Но вообще конечно в геймдеве всё на массивах, а иначе как ты собрался SIMD-видеокартой это обрабатывать?

khrundel ★★★★
()
Ответ на: комментарий от eao197

Тайм-ауты одинаковые, что дает возможность просто добавлять новые таймеры в конец списка, без поиска подходящего места вставки.

:)

Ладно, признаю, в данном случае список выглядит удобнее чем массивы (вектор/дек). Не эффективнее, а просто удобнее. Хотя и тут я вижу потенциальную проблему с конфликтом отмены и наступления таймаута, возможно в реальной задаче где отмена может и не прийти, а может прийти, в том числе и после таймаута, защита от подобных проблем сожрёт всё удобство и последовательные id таймера были бы лучше.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

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

Там нет никах проблем, особенно если список интрузивный. Достаточно в описателе таймера иметь метку его текущего статуса.

eao197 ★★★★★
()
Ответ на: комментарий от crutch_master

В таком случае её нужно грохнуть.

Совсем дурак что ли? Впрочем да, странный вопрос. В теории графов изучают понятие связности, в графе выделяют от 1 до количества вершин компонентов связности. Считай все задачи на эту тему у тебя автоматом нерешаемы становятся.

Ну и вообще, играет игрок в simcity, дорогу удалил - город пропал.

Тогда в чём проблема?

При освобождении графа 2 раза вершину грохнешь, вот в чём. Ты же отказался от дополнительного контейнера для вершин.

Зачем их перечислять? Чтобы что?

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

Если он тебе нужен. Ты подминаешь реальность под свои ограниченные взгляды.

Lol, ну давай представим, что вот реально не нужен тебе общий контейнер. Память ведь только слабаки освобождают. Вот ты запилил свой граф, реализовал нужные операции через задницу, но как-то обошёлся без общего списка вершин. А потом натыкаешься на задачу, которая без этого списка нерешаема. Могут же требования измениться? Или мог ты ошибиться и не понять сразу что вот эта штука без списка нерешаема. И ты послушно добавляешь общий список. Попутно рефакторишь уже сделанные подзадачи, убирая кривые костыли и переделывая на использование списка. А теперь вопрос: зачем всё это было? Если можно изначально нормально было сделать?

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

khrundel ★★★★
()
Ответ на: комментарий от eao197

Достаточно в описателе таймера иметь метку его текущего статуса.

Нет, ты не можешь иметь метку текущего статуса в таймере, который уже удалён. Т.е. тебе приходит указание «отмени таймер по адресу 0x12345abcdef» а это или живой таймер, или свободная память в хипе, или уже какие-то данные, или новый таймер, аллоцированный по тому же адресу. В дескрипторе нужно иметь возможность грохнуть задачу, которая может отменить, либо нужно RC на таймер из списка и из задачи-отменятора.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Нет, ты не можешь иметь метку текущего статуса в таймере, который уже удалён.

Он не может быть физически удален пока кто-то держит на него ссылку.

нужно RC на таймер из списка и из задачи-отменятора.

Да.

eao197 ★★★★★
()
Ответ на: комментарий от crutch_master

Не потребуется для списка второй элемент найти. Если надо искать n-ый элемент берётся массив.

Гениально. Завести список, чтоб удобно удалять ноды из середины без мува. Завести массив, чтоб искать эти ноды из середины не тратясь на обход списка. При удалении ноды обновлять индекс, перемещая содержимое индексирующего массива. А в особо упоротых случаях, когда удалять можно не только по индексу, но и, например, по условию, сначала долго обходить список в поисках элемента для ужаления, а потом ещё пробегать индексирующий массив, разыскивая по какому там индексу указатель на удаляемую ноду.

khrundel ★★★★
()
Ответ на: комментарий от aist1

Вставка в конец O(1) у него амортизированная, что значит, что на N операций O(1) будет одна операция О(N) (худший случай).

Отличное слово «амортизированная», буду знать. Хотя именно на это обстоятельство я и намекал, когда писал, что кое-кому следует меньше хамить, а больше подучить матчасть. В задачах реального времени такое не пойдёт. Думаю, настало время извиниться за хамство.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

И можно собирать одно приложение из разных объектных файлов собранных разными стандартами.

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

В C99 был добавлен логический тип _Bool

Можем ли мы определять интерфейс, по которому обмениваются наши объектны файлы, с использованием типа _Bool? Вряд ли. Как минимум, нужно будет _что_то сделать с программами, написанными на более ранних диалектах Си. А в худшем случае там такой _Bool уже будет. Вот отсюда и возникают ограничения.

den73 ★★★★★
() автор топика
Ответ на: комментарий от eao197

На лиспе занимался и на Си, но тут не нужно быть курицей. В реальном времени требуется оценка сверху времени выполнения операции. А тикль так-то вообще язык вовсе не маргинальный, как ты в своей кляузе на меня пытался изобразить. И в промышленности (где могут быть требования к времени отклика) как раз распространён, например, он присутствует в vxWorks. В ANSYS и средствах разработки Xilinx реальное время менее по делу, но там он тоже есть. Ты, конечно, сделал продукты уровня vxWorks, ANSYS или Petalinux?

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от khrundel

Но вообще конечно в геймдеве всё на массивах, а иначе как ты собрался SIMD-видеокартой это обрабатывать?

О, даже от тебя какая-то польза бывает. Хорошее наблюдение.

den73 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Знаешь, беру свои слова обратно. Даже в случае таймеров как ты описал, решение на списках хуже массивного, причём как по производительности, так и по удобству.

В качестве айдишников берём монотонно растущие целые числа. Удаление из начала тривиально, просто проверять статус. Для очереди используем, внезапно, очередь. Отмена через:

if (timers_deque.size() > 0)
{
    int64_t index = timer_id - timers_deque[0].timer_id;
    if (index >= 0)
        deque[index].canceled = true;
}

И никакой дрочки счётчиков ссылок, никаких ненужных аллокаций.

khrundel ★★★★
()
Последнее исправление: khrundel (всего исправлений: 1)
Ответ на: комментарий от den73

Но как обеспечивается совместимость интерфейсов? Для этого же нужно скомпилировать с неким заголовочным файлом, где эти интерфейсы описаны. И по нему начинают пересекаться все стандарты. Я плюсы плохо знаю, но на примере Си рассмотрим. Си я тоже знаю плохо, но достаточно открыть Википедию и прочитать там:

Ну да, это нужно чтобы и сторонние библиотеки не делали странного. Но для компилятора и STL это соблюдается, как и для многих сторонних библиотек…

Недавно спрашивали о таком, потому что видимо не все знают:

https://github.com/microsoft/STL/issues/2887#issuecomment-1190798636

fsb4000 ★★★★★
()
Ответ на: комментарий от khrundel

решение на списках хуже массивного, причём как по производительности, так и по удобству.

Ну я сделал все что мог.

eao197 ★★★★★
()
Ответ на: комментарий от fsb4000

Это я в целом ответил на то, почему поддерживать в одном продукте целую линейку стандартов - дорого. Нужно знать, обдумать, и принять решение по каждому отличию. Поэтому, если некий продукт X совместим с жирным продуктом Y - это уже удар по возможностям продукта X. Если он совместим с Y1,…,YN - то это сокрушительный удар. Потому что для составления продукта X нужно решить огромное число уравнений. Если N растёт со временем, то и система усложняется. Возникают неразрешимые куски, приходится ампутировать функционал из X только ради сохранения совместимости.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

На лиспе занимался и на Си

При этом вы и Си толком не знаете: «Си я тоже знаю плохо» (с) den73

Я как бы вам мягко намекаю, что в реальном времени у вас вообще динамической памяти не будет. Поэтому там для векторов амортизированной оценке неоткуда будет взяться: вектор не сможет просто так при добавлении (n+1) элемента взять и вырасти в своих размерах.

Да и списки, если и будут использоваться, то из преаллоцированных нод.

И в промышленности (где могут быть требования к времени отклика) как раз распространён, например, он присутствует в vxWorks. В ANSYS и средствах разработки Xilinx реальное время менее по делу, но там он тоже есть. Ты, конечно, сделал продукты уровня vxWorks, ANSYS или Petalinux?

Ruby и Python распространены еще больше, это не значит, что на них делают что-то отдаленно приближенное к реальному времени.

Хотя в последние лет 10-15 под real-time понимают даже то, что скорее следует назвать online processing. Так что не удивлюсь, если это именно то «реальное время», с которым вы имели дело.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от khrundel

Ну и вообще, играет игрок в simcity, дорогу удалил - город пропал.

Если узел ни с чем не связан и нахер не нужен - да, пропал. Бывает и такое.

Ты же отказался от дополнительного контейнера для вершин.

Мне не нужен контейнер - я его не использую. Нужен - использую. Это у тебя альтернативы нет.

Если можно изначально нормально было сделать?

А если это изначально нужно не было, то что? Делать все равно надо было с лишними костылями? Ты какой-то странный.

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

Сектант, ты протек. У тебя всё, что не укладывается в твою картину мира - не человеческое и т.д. Разупорись. Претензии не к массиву, а к твоей упоротости.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 3)
Ответ на: комментарий от khrundel

Гениально. Завести список, чтоб удобно удалять ноды из середины без мува.

списки это не для быстрого доступа по индексу. и нет там никакого «удаления из средины» поскольку «средина списка» - бессмысленное для списка понятие.

список это упорядоченное множество,перебираются там элементы либо все последовательно - операция типа for_each, либо вообще не перебираются.

типовая общая иллюстративня задача - есть N обьектов, и M множеств в которых они могут находиться. есть какие-то условия по которым обьекты из одного множества попадают в другое. реализовывать это массивах может только псих. поскольку ему придется иметь M массивов с указателями на обьекты, размером не менее N, которые в основном будут пустыми.

достоинство массива не скорость перебора(у списка тоже высокая скорость перебора), а рандомный доступ по индексу!, что для массива - одна операция 0(1), а для списка - O(n). все остальное у массива - сплошные недостатки.

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

вставки/удаления на массиве инвалидируют все ранее взятые индексы.

то есть, если есть два треда - один вставляет в множество обьект, а другой что-то с этими обьектами делает, то на массивах это написать весьма сложно, - поскольку вставка будет инвалидировать индексы, то второй тред сломается, если их имеет.

на списках же все происходит легко и приятно, вставка/удаление защищаются мьютексом и все.

«массив» это такое представление, что обеспечивает рандомный доступ по индексу за константное время.

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

alysnix ★★★
()
Ответ на: комментарий от khrundel

Я хз, зачем ты это высрал, честно. Сам проблему придумал, сам её героически обосрал.

crutch_master ★★★★★
()
Ответ на: комментарий от eao197

Хотя в последние лет 10-15 под real-time понимаю даже то, что скорее следует назвать online processing.

Я занимался системой gensym g2, это не секрет, т.к. это строчка из резюме. Чем именно занимался и что там внутри - я хотел бы рассказать, но не буду. Можешь пособирать инфу из открытых источников.

den73 ★★★★★
() автор топика
Ответ на: комментарий от alysnix

Да он упорот в щи, что ему объяснять? Раз на русте нет ссылочных структур, значит они не нужны. Всё. Есть вот вектор, значит ты все должен пихать в вектор. Все должны всё пихать в вектор. Всё равно же вектор по итогу нужен, ведь так? Не нужен? Нет, вы не правы, азаза, вектор лучше, а вы все говноделы, кококо.
Я столько раз это слышал, когда чел что-то тупо не может реализовать и начинаются тупейшие отмазки в таком стиле. Со всеми этими же аргументами. Сначала блеяние про не нужно, потом «вы все тупые», а потом разгребаешь за ними то говно, что получилось, потому что они не шмогли, а ты же умный, сделай.

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 3)
Ответ на: комментарий от den73

Я занимался системой gensym g2

Смотрим:

G2 transforms real-time operations data into automated decisions and actions, all in real time. G2 applications work in concert with existing operational systems, including enterprise systems, databases, automation systems, data historians, network management systems, telemetry systems, and many more.

Как раз то, о чем я и говорю: он-лайн обработка данных (т.к. как пришли, так сразу обработались и выдали результат). Но для маркетинга почему бы и не обозвать real-time. Могу предположить, что настоящим реальным временем там нижележащие SCADA системы занимались.

Хотя, полагаю, под формальные определения real-time, когда нужно всего лишь уложиться в заданной временной интервал, подогнать не сложно.

eao197 ★★★★★
()
Ответ на: комментарий от a--

но все же как насчет точной конвертации по запросу программиста?

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

DarkEld3r ★★★★★
()
Ответ на: комментарий от crutch_master

Нет, про геймдев он что-то разумное сказал. Я правда почему-то думаю, что и там не всё на массивах, а только то, что подлежит обработке на SIMD карте. Но тут я вообще не в зуб ногой.

den73 ★★★★★
() автор топика
Ответ на: комментарий от fsb4000

И фичи какие-то добавляются, какие-то выкидываются.

И много ли выкинулось? По моему, случаи можно на пальцах одной руки пересчитать. Плюс в основном выкидывали то, что и так не работало или не использовалось. Например, поддержку GC.

И можно собирать одно приложение из разных объектных файлов собранных разными стандартами.

Удачи, провернуть это, если поменялось abi.

Без понятия почему в расте используется эпохи, и некоторые говорят что в С++ нужны эпохи, когда отличий от стандарта нет никаких.

Даже если закрыть глаза на то, что компиляторы никто не обязывает поддерживать прошлые стандарты (а это главная фича), то фактическое отличие, как минимум, в том, что (С++) стандарты на 99% обратно совместимые.

DarkEld3r ★★★★★
()
Ответ на: комментарий от khrundel

Знаешь, беру свои слова обратно. Даже в случае таймеров как ты описал, решение на списках хуже массивного, причём как по производительности, так и по удобству.

не знаю что за таймеры вы там мусолите, но реально таймеры выглядят так.

на с++: таймер это обьект класса таймер. он создается программно, и «активируется» на срабатывание в момент времени t.

для этого вычисляется время его срабатывания (текущее+заданный интервал) и он вставляется в сортированный по моментам срабатывания список таймров (чем раньше сработает, тем ближе к голове), в нужное место. список этот интрузивный естессно.

потом по таймерному прерыванию или еще какому временному сигналу от ОС или хардвара, список активных таймеров просматривается от начала,- если первый таймер «созрел» он извлекается из списка, и пускается его хук или виртуальный метод. если таймер периодический, то он вставляется обратно в сортированный этот список… берется снова голова списка и все повторяется, если этот таймер «созрел». если не созрел - перебор преращается.

таким образом по интеррапту или сигналу пускаются созревшие таймеры и ведется их список.

если таймер удалили, а он в списке активных, он безболезненно удалается оттуда за констатное время. список этот защищен мьютексом или монопольным режимом, то есть блокируется шедулер, пока в этом списке ковыряются.

и не надо ничего выдумывать на «массивах». массив это только для рандомного доступа. а рандомный доступ тут не нужен вообще.

alysnix ★★★
()
Ответ на: комментарий от DarkEld3r

Вот как раз миграция - это адекватный подход, и если она возможна, то это говорит в пользу языка. А поддерживать совместимость с N версиями - нет, ну богатые типа Микрософта тоже это могут.

den73 ★★★★★
() автор топика
Ответ на: комментарий от DarkEld3r

И много ли выкинулось? По моему, случаи можно на пальцах одной руки пересчитать.

Триграфы, ключевое слово register, изменен смысл ключевого слова auto. Может ещё что-то, но да не сильно много чего удаляли.

Удачи, провернуть это, если поменялось abi.

Ну да, благодаря тому что ABI не меняется в разных стандартах, то возможность собирать приложение где разные объектные файлы собраны с разными стандартами даётся бесплатно.

fsb4000 ★★★★★
()
Ответ на: комментарий от den73

А поддерживать совместимость с N версиями - нет, ну богатые типа Микрософта тоже это могут.

Можешь объяснить в чём разница с практически всеми существующими языками, где обратную совместимость ломают очень редко и только по мелочам? Там точно такое же «поддержание совместимости со всеми версиями», только версии менее явные.

DarkEld3r ★★★★★
()
Ответ на: комментарий от alysnix

но реально таймеры выглядят так.

Все несколько сложнее: есть несколько дисциплин (механизмов) обслуживания таймеров, которые заточены под разные сценарии и разное количество этих самых таймеров. Я в свое время реализовывал три наиболее употребительных и более-менее универсальных: timer-wheel, timer-heap и timer-list. В библиотеке ACE, емнип, еще один или два дополнительных механизма есть.

Для timer-wheel и timer-heap применяются массивы. Причем для timer-wheel он преаллоцированный и фиксированного размера. Правда, из этого массива, в простом случае, идут ссылки на двусвязные списки таймеров.

eao197 ★★★★★
()
Ответ на: комментарий от fsb4000

Триграфы, ключевое слово register, изменен смысл ключевого слова auto.

+auto_ptr, +спецификация исключений для функций/методов (тот самый невзлетевший throw(exception)).

eao197 ★★★★★
()
Ответ на: комментарий от DarkEld3r

Так существующие языки через это и вымирают, точнее, стагнируют и в этот момент новые языки получают шанс вырваться вперёд ввиду того, что ошибки, допущенные в старых, уже известны, а груз наследия не мешает их исправить.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Может ещё что-то

Ещё экспорт для шаблонов.

Ну да, благодаря тому что ABI не меняется в разных стандартах

Прям никогда? (:

А как же CоW строки, которые были раньше в GCC?

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

А как же CоW строки, которые были раньше в GCC?

Там решили это с inline namespace. То есть там сейчас есть две версии std::string, и можно собирать с разными стандартами и для gcc тоже.

Там даже больше, благодаря inline namespace, у этих типов разный манглинг и они не мешают друг другу и там можно собирать даже с двумя разными стандартными библиотеками libc++ и libstdc++ и это будет работать…

fsb4000 ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)