LINUX.ORG.RU

Контейнеры в C


2

3

Будучи сиплюсплюсником, меня давно интересует как те же задачи выполняются в C. Знаю, на ЛОРе есть множество приверженцев C, надеюсь они ответят на пару простых вопросов.

Я являюсь активным сторонником идеи «Алгоритм должен работать настолько быстро, насколько позволяет железо». С этой точки зрения C++ даёт потрясающие возможности из-за своей системы кодогенерации. Да, я имею в виду шаблоны.

Не будем зарываться в дебри boost'а, возьмём простую задачу - контейнеры.

Для примера я взял односвязные списки в GTK GSList и Qt QList. QList позволяет хранить как простые, так и сложные типы с конструкторами, деструкторами, типы с общими данными. При этом накладных расходов на выделение в куче не происходит, а при реаллокации выбирается нужный алгоритм в зависимости от QTypeInfo<T>, к примеру для int будет вызван memcpy(), а для QString оператор копирования. Кроме того блок данных заранее резервируется и для сложных типов вызывается placement constructor. Для удаления данных по указателям используется алгоритм qDeleteAll(from,to), который сам дёрнет нужные конструкторы. Беглый просмотр GSList показал, что в нём можно хранить только указатели, со всеми вытекающими накладными расходами на аллокацию/уничтожение памяти, ручное кастирование, слежение за утечками, фрагментацию памяти.

Аналогичная ситуация со связными списками GList и QLinkedList.

Это даже не затрагивая вопрос о типизации, в C++ компилятор сразу даст по рукам при попытке записать в контейнер неверный тип или с помощью неявного преобразования с explicit-конструктором.

Далее, счётчики ссылок и деструкторы.

К примеру, в C++ список строк будет выглядеть как QList<QString>, при этом можно забыть про внутреннюю структуру строки - конструктор, деструктор и операторы копирования сами занимаются подсчётом ссылок, разделением и уничтожением данных. Вернуть строку из функции проще простого:

QString foo()
{
    return listOfStrings.at( 5 );
}

Этот код абсолютно безопасен и оптимален с точки зрения использования памяти и процессора, поскольку время тратится только на увеличение счётчика и копирование указателя.

В GTK я сходу нашёл GString:

struct GString 
{
  gchar *str;
  gint len;
};

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

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

Или может GTK неудачный пример, тогда дайте ссылку на правильную C-библиотеку с контейнерами.

★★★★★
Ответ на: комментарий от MuZHiK-2

>>а что не так с шаблонами и почему Вы называете их портянками? почему многокилометровые?

Видимо, ты не видел серьезного кода на шаблонах и не отлаживал их.

и видел и отлаживал, поэтому Вас и спрашиваю что же там не так :)

>>множественное наследование - это всего лишь парадигма, не нравится - никто использовать не заставляет :)

Ой как мы сразу зачесались-то! Стоило только тыкнуть носом - сразу кричать «это не мое!», да?

да, мне не нравится концепция множественного наследования, и? что Вы суетитесь то так?

Нет уж, раз кресты такие клевые, используй весь спектр их «клевости».

спасибо, но без Ваших советов я прекрасно жил и, думаю, и дальше проживу :)

Иначе от крестов ничего не останется, получится голый С.

толсто, либо всё либо - ничего, тут попахивает психологией школоты

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

>>Он просто хотел увидеть, как реализовать наиболее правильно на С описанную им задачу.

Ему указали на GList и GArray, но он продолжил разводить неприятные запахи.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от Reset

в std::unordered_map хеш задается третьим параметром

в std::hash_map ЕМНИП тоже, но в 99% случаев подбор функции считающей хэш для конкретного случая не нужен и не очень продуктивен

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

>>эм, а просто с указателями в данном случае Вы не поимеете проблемы? :)

Поимею. Я к тому, что в крестах тоже нет панацеи от всего.

мы же ведь уже обсудили недостатки данного подхода, вот тут, или снова начнём?

Там был просто срач.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shty

>>и видел и отлаживал, поэтому Вас и спрашиваю что же там не так :)

Ты перепутал шаблоны с Сейлор Мун.

да, мне не нравится концепция множественного наследования, и? что Вы суетитесь то так?

То есть, не хочешь использовать всю мощь крестов?

MuZHiK-2 ★★★★
()
Ответ на: комментарий от Eddy_Em

Когда-то очень давно я тоже так делал, но потом меня так за2.71бала эта возня и нагромождения из бесконечных аллокаций/деаллокаций, что я стал писать по-другому. Сейчас математику я пишу так — алгоритмическое ядро (числодробильня) работает с double * и написана на чистом Си, а вот высокоуровневый код, который подготавливает данные и вызывает функции ядра это Си++ и stl. При этом в моих программах нет ни одного явного выделения памяти. Код больше не загроможден и читается/понимается очень легко в том числе и посторонними людьми. Ну и конечно же случайно испортить его нельзя, так как в отличие от Си, если я что-то добавляю/убираю, то делаю это только в одном месте.

Reset ★★★★★
()
Ответ на: комментарий от MuZHiK-2

внезапно, refcount используют для подсчёта ссылок :)

Ты дурак что ли?

спасибо сэр, Вы сама вежливость

напоминаю: переход на личности чаще всего бывает вызван отсутствием аргументов

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

во-первых не обычно, а в данной конкретной реализации

во-вторых сам по себе «подсчёт ссылок» ничто другое нежели инкремент/декремент значения счётчика

>>хорошо, давайте с другой стороны, как подсчёт количества ссылок поможет освободить ресурсы при удалении объекта?

Просто: если refcount становится равным 0, то вызываются методы _dispose() и _finalize(), где ты можешь освободить ресурсы объекта так, как пожелаешь.

эм, можно я усомнюсь в Ваших способностях к прочтению и анализу того что Вам было написано?

если refcount != 0 (будем использовать Вашу терминологию) и объект удаляется что произойдёт?

Да, сынок,

я тебе не сынок, не заговаривайся

shty ★★★★★
()
Ответ на: комментарий от MuZHiK-2

Только в случае локально созданных объектов. Как только начинаются указатели - тоже приходится следить.

В нормальном C++ коде указатели за которыми надо следить встречаются очень редко.

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

Это решается оборачиванием объекта в блок {}

Reset ★★★★★
()
Ответ на: комментарий от MuZHiK-2

>>эм, а просто с указателями в данном случае Вы не поимеете проблемы? :)

Поимею. Я к тому, что в крестах тоже нет панацеи от всего.

где утверждалось обратное?

>>мы же ведь уже обсудили недостатки данного подхода, вот тут, или снова начнём?

Там был просто срач.

а здесь что, сложносрач? :) учитесь использовать информацию

shty ★★★★★
()
Ответ на: комментарий от MuZHiK-2

Я знаю только одну платформу где этого нет. Это SCO в которой до сих пор в качестве компилятора используется cfront, а поэтому нет stl'я и тем более boost'а :)

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

>>напоминаю: переход на личности чаще всего бывает вызван отсутствием аргументов

Сынок, там стоял вопрос, если что. Я же не видел твоих медсправок.

во-первых не обычно, а в данной конкретной реализации

Пруф?

во-вторых сам по себе «подсчёт ссылок» ничто другое нежели инкремент/декремент значения счётчика

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

если refcount != 0 (будем использовать Вашу терминологию) и объект удаляется что произойдёт?

Просто удалится переменная указателя на объект, сам объект останется в памяти.

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

и видел и отлаживал, поэтому Вас и спрашиваю что же там не так :)

Ты перепутал шаблоны с Сейлор Мун.

нет, но судя по твои комментарием ты регулярно путаешь программирование с просмотром анимэ для детей

>>да, мне не нравится концепция множественного наследования, и? что Вы суетитесь то так?

То есть, не хочешь использовать всю мощь крестов?

я использую то что мне удобно и позволяет решить мою задачу :) синтаксисодрочеры и пуристы идут лесом

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

>>В нормальном C++ коде указатели за которыми надо следить встречаются очень редко.

Если использовать кресты только для высокоуровневых вещей - да. Но как только будешь спускаться вниз - указатели неизбежны.

Это решается оборачиванием объекта в блок {}

Ну вот ты в блоки заворачиваешь (следишь за этим), кто-то за указателями следит.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от ahonimous

ну х.з. в конторе в которой я когда-то работал использовался 5'й OpenServer и cfront.

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

>>Я знаю только одну платформу где этого нет. Это SCO в которой до сих пор в качестве компилятора используется cfront, а поэтому нет stl'я и тем более boost'а :)

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

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

Но как только будешь спускаться вниз - указатели неизбежны.

ага, только у меня они там возникают не как результат new/malloc, поэтому я за ними не слежу

Ну вот ты в блоки заворачиваешь (следишь за этим)

Не слежу, само все делается. «Следить» это гораздо более сложная операция, так как надо увидеть не только место в котором объект больше не нужен, но и всякие неожиданные ситуации типа исключений и неожиданных return'ов из середины функции.

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

>>я использую то что мне удобно и позволяет решить мою задачу :) синтаксисодрочеры и пуристы идут лесом

Вот и я о чем. Удобство штука субъективная. ТС же произвел столько метана, из-за того, что не осилил указатели. Меня лично указатели не напрягают.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от Reset

> hash_map не входит в стандарт, это самодеятельность sgi. в стандарте только будет unordered_map

smart_ptr на данный момент тоже - но это не мешает его использовать

ahonimous
()
Ответ на: комментарий от MuZHiK-2

>>во-первых не обычно, а в данной конкретной реализации

Пруф?

пруф чего тебе? по каким алгоритмам очистка памяти в GC делается? иди читай, образовывайся

>>во-вторых сам по себе «подсчёт ссылок» ничто другое нежели инкремент/декремент значения счётчика

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

спасибо сэр, а то я уж думал до Вас никогда не дойдёт в чём разница

>>если refcount != 0 (будем использовать Вашу терминологию) и объект удаляется что произойдёт?

Просто удалится переменная указателя на объект, сам объект останется в памяти.

да, и это называется утечка памяти

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

>>Там C++ ? Если есть, то есть и stl и boost.

Мне как-то приходилось писать код (расчет корреляционных матриц и подобные вещи) на железку для военных, так вот там С++ не было - все было написано на С, компилятора С++ под их обрезанную среду вообще не было. Да, это была их какая-то «чудо» техника, но пришлось писать на том, что есть. Наверное, есть и другие платформы без С++.

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

где утверждалось обратное?

Посмотри высказывания ТС про его 100% классный код.

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

shty ★★★★★
()
Ответ на: комментарий от MuZHiK-2

>>я использую то что мне удобно и позволяет решить мою задачу :) синтаксисодрочеры и пуристы идут лесом

Вот и я о чем. Удобство штука субъективная. ТС же произвел столько метана, из-за того, что не осилил указатели. Меня лично указатели не напрягают.

я вот только одного не понимаю, если Вас даже указатели не парят, то почему так парит ТС и его высказывания?

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

hash_map не входит в стандарт, это самодеятельность sgi. в стандарте только будет unordered_map

у меня такое смутное чувство как будто весь stl - это и есть самодеятельность sgi, не?

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

>>пруф чего тебе? по каким алгоритмам очистка памяти в GC делается? иди читай, образовывайся

Пруф по тому, что ты сказал.

да, и это называется утечка памяти

Это называется «ты не знаешь, о чем говоришь» и на выходе получается чушь. Никакой утечки не будет. Иди прочитай хотя бы как работает refcount в glib, перед тем, как лезть с такими глупостями к большим дядям: http://library.gnome.org/devel/gobject/unstable/gobject-memory.html

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shty

>>возможно он где-то и перегнул палку, но это вовсе не повод доказывать ему это теми методами которые применяете Вы

Он полез в ту область, где почти не разбирается, полез с криками «Я лучший и все знаю, в дураки до меня не смогли додуматься!». Обычно у нас в деревне за такие вылазки в огороды стреляли солью по жопе.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shty

>>я вот только одного не понимаю, если Вас даже указатели не парят, то почему так парит ТС и его высказывания?

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

MuZHiK-2 ★★★★
()
Ответ на: комментарий от Reset

>>Это не означает, что надо всегда писать на голом Си.

Само собой. Но ведь затык ТС был в том, что на С нельзя сделать обобщенный контейнер. Ему указали на реализацию - но баттхерт не остановился. Мне самому приходится работать и с Qt, и с сишным кодом, но я спокойно нахожу инструменты под задачу, а не ору об «ущербности» другого языка только потому, что там сделано все не так, как в быдлокуте. В каждом языке свои принципы, свои идеи и свои парадигмы.

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

пруф чего тебе? по каким алгоритмам очистка памяти в GC делается? иди читай, образовывайся

Пруф по тому, что ты сказал.

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

>>да, и это называется утечка памяти

Это называется «ты не знаешь, о чем говоришь» и на выходе получается чушь. Никакой утечки не будет.

то что описал - утечка памяти в явном виде, не юли

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

>>я ведь уже сказал: иди читай, образовывайся, это слишком большой вопрос чтобы я тебе его здесь разжёвывал

Хорошо, записал тебе слив.

то что описал - утечка памяти в явном виде, не юли

Ты точно хорошо себя чувствуешь и прочитал тот линк, который я тебе дал? Если ты линк не читал, то говорить с тобой, сынок, у нас не получится, потому что ты не в теме.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от namezys

Мне все читать лень, а пообсуждать хочу.

а что стесняешься-то? для этого даже тему знать не надо :) просто берёшь и на первое попавшийся пост отвечаешь, если что потом скажешь что всю вселенную нельзя вместить в 2 предложения, проблема рассматривается слишком узко, а тебя вообще не так поняли :)

О чем это вы щас?

тема месяца плюсосрачей: реализация обобщённых контейнеров в голом си

shty ★★★★★
()
Ответ на: комментарий от MuZHiK-2

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

Он полез в ту область, где почти не разбирается

Вы то это откуда узнали, опять libastral подключаете не к месту?

полез с криками «Я лучший и все знаю, в дураки до меня не смогли додуматься!»

пруф не было такого

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

и теперь Вы на ЛОРе сидите стоя? :)

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

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

namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2

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

Хорошо, записал тебе слив.

зачем мне твой слив?

>>то что описал - утечка памяти в явном виде, не юли

Ты точно хорошо себя чувствуешь и прочитал тот линк, который я тебе дал?

я настоящий Ъ, а «то что ты описал - утечка памяти в явном виде», так что не юли

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

> конечно, читать sys/tree.h :)

Вы шутите, или серьезно?

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

Если на С и можно использовать статический полиморфизм, то через извращенные макросы. Так что быстрые контейнеры на С превратятся в набор неуправляемых макросов

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

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

>>Вы то это откуда узнали, опять libastral подключаете не к месту?

То, что он GLib путает с GTK и, зачем-то полез «В GTK я сходу нашёл GString» говорит об отсутствии должной компетенции в данном вопросе.

пруф не было такого

А это чьи высеры?

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

и теперь Вы на ЛОРе сидите стоя? :)

Причем тут я?

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shty

> вообще-то есть способ избавится от гемора с отладкой макросов - это разработка через тестирование (TDD), но всё равно упаришься

Ой ли. Как оно спасает?

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

>>зачем мне твой слив?

Потому что я не увидел от тебя пруфа на твой же высер.

я настоящий Ъ, а «то что ты описал - утечка памяти в явном виде», так что не юли

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

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

полез с криками «Я лучший и все знаю, в дураки до меня не смогли додуматься!»

пруф не было такого

А это чьи высеры?

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


это не пруф на высказывание которое Вы, как теперь видно, просто приписали ТС

shty ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.