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-библиотеку с контейнерами.

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

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

Это пруф, и если ты прочитаешь мои посты раньше, я там указал, почему он ошибается. Поэтому это высер а ля «Я лучший!».

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

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

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

вовсе и нет, когда Вы скачиваете gtk+, Вам предлагается скачать и glib (пруф), так что вероятнее всего указанный случай - просто ассоциация, а не то что Вы себе надумали

Вы часто делаете очень скоропалительные выводы, это Вас характеризует не с лучшей стороны

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

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

Это пруф,

ещё раз - это не пруф, из приведённой цитаты не следует что ТС имел в виду то что Вы ему приписываете

и если ты прочитаешь мои посты раньше...

я Вас попросил привести пруф - Вы привели, к несчастью он оказался несостоятельный, что ещё тут надо? может в БСЭ поискать?

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

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

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

>>когда Вы скачиваете gtk+, Вам предлагается скачать и glib (пруф), так что вероятнее всего указанный случай - просто ассоциация, а не то что Вы себе надумали

А еще в ИЕ всплывает баннер с голыми тетками, когда я хочу скачать. И могут возникать любые ассоциации. Поэтому мне все равно, что он там подумал (или вообще не подумал), но за базар, как говорится, надо отвечать.

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

тогда и мне не пришлось бы тебя макать.


Друзья! Хватит ссориться, Давайте уже «макать» «кепку с длинным хоботом».

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

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

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

это не высер, а объективная реальность, не нравится - ешьте кактус

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

Сынок,

в который раз тебе говорю: «я тебе не сынок», что трудно запомнить? следующий раз пруф попрошу, так и знай

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

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

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

когда Вы скачиваете gtk+, Вам предлагается скачать и glib (пруф), так что вероятнее всего указанный случай - просто ассоциация, а не то что Вы себе надумали

А еще в ИЕ всплывает баннер с голыми тетками, когда я хочу скачать.

в странных местах Вы gtk качаете :)

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

Вы бы начали с себя

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

>>ещё раз - это не пруф, из приведённой цитаты не следует что ТС имел в виду то что Вы ему приписываете

Значит у тебя проблемы с логикой, писать на С лучше не пытайся.

к несчастью он оказался несостоятельный,

Сынок, может включишь мозг немного? Я привел тебе пруф несостоятельности высеров ТС, а ты мне так и не привел пруф на то, что я тебя просил, и облажался с refcount-ом.

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

Видать, С++ плохо влияет на твою голову. Проветрись.

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

Приведи еще раз пруф - я почитаю.

Меня давно интересовало, как можно более или нормально на С сделать статический полиморфизм

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

>>это не высер, а объективная реальность, не нравится - ешьте кактус

Я же и говорю - ты слился и увяз с массе. Будешь дергаться - будет хуже.

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

Сынок, а давай проверим твою память? а ну-ка, покажи мне пруф того, что оставление объекта в памяти с refcount != 0 - это утечка памяти с точки зрения GObject. Я жду.

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

>>Вы бы начали с себя

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

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

>>Меня давно интересовало, как можно более или нормально на С сделать статический полиморфизм

Я сейчас веду разговор об обобщенных контейнерах, если что.

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

Я сейчас веду разговор об обобщенных контейнерах, если что.

здорово! значит ты можешь показать аналог:

map<string,Person> persons;
persons[ "name" ] = { "state", 38 };

на С?

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

> Я сейчас веду разговор об обобщенных контейнерах, если что.

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

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

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

Только не говори, что ты тоже С не видел, как и ТС. Посмотри сперва на GList и GArray, возможно вопросы отпадут.

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

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

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

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

> Ссылку я тебе дал, описание работы с типом есть. Указанная задача с помощью данного типа решается. Дальше - сам, за бесплатно я твоим образованием заниматься не буду. Может еще работу за тебя сделать?

ты слишком предсказуем и толст

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

> Может раскажешь?

Может еще работу за тебя сделать? (c)

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

и вообще что ты человека отвлекаешь - думаешь он тут просто так тут два часа сидит? нет - он очень важные вещи пишет, а ты ему мешаешь

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

>>ты слишком предсказуем и толст

Боюсь предположить, с чем у тебя проблемы, что ты не осиливаешь пару строчек кода.

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

>>Я просто не знаю как это сделать без изврата с макросами. Может раскажешь?

Опиши проблему на примере, что у тебя там не получается.

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

> Тогда что ты хочешь от меня, если ты задачу уже решил?

уже ничего - думаю всем очевидно, что ты ее решить в две строки на С не сможешь

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

код на С++


template<typename F>
void ff(F self);

void ff(int self);

...

ff("afdfsad");
ff(123);



Вот классический пример статического полиморфизма: вызываемые функции зависят от типа аргумента. Как такое на С сделать?

ЗЫ: я не стал писать нагромождение с классами, хотя могу
namezys ★★★★
()
Ответ на: комментарий от ahonimous

>>уже ничего - думаю всем очевидно, что ты ее решить в две строки на С не сможешь

Во-первых, давно количество строк стало показателем качества и скорости?

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

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

Я понял о чем ты. Но не понял, к чему ты приплел это в данном топике. У нас речь об обобщенных контейнерах и их реализации в С.

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

> ты не осиливаешь пару строчек кода.

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


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

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

Ладно. Я хочу использовать обычный вектор с целочисленным индексом. При переаллокации потребуется скопировать все объекты. Для этого есть специальная функция - конструктор копирования (пусть она называется как в С++).

1) Как С компилятор определит эту функцию, зная только тип объектов в массиве.

2) Иногда, некоторые объекты можно копировать побайтово. Тогда выгодно скопировать всю область памяти. Как на С компиляторе решить эту задачу?

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

ещё раз - это не пруф, из приведённой цитаты не следует что ТС имел в виду то что Вы ему приписываете

Значит у тебя проблемы с логикой

что-то мне подсказывает что моими якобы «проблемами с логикой» ты прикрываешь свои проблемы с пруфами

Сынок,

пруф или не было

Я привел тебе пруф несостоятельности высеров ТС

пока что ты привёл много пруфов несостоятельности себя и продолжаешь приводить

а ты мне так и не привел пруф на то, что я тебя просил,

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

и облажался с refcount-ом.

о да, это же я сравнил подсчёт ссылок и конструкторы/деструкторы :) пешы ищо, афтар (с)

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

> Ладно. Я хочу использовать обычный вектор с целочисленным индексом. При переаллокации потребуется скопировать все объекты. Для этого есть специальная функция

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

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

а ну-ка, покажи мне пруф того, что оставление объекта в памяти с refcount != 0 - это утечка памяти с точки зрения GObject

ты так и не понял что мы с тобой не gobject обсуждаем? так у тебя не с логикой того, ты слоупок, что ж сразу не сказал?

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

>> Как С компилятор определит эту функцию, зная только тип объектов в массиве.

man realloc, не?

Я про функцию копирования говорил, а не перевыделения памяти

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

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

//fixed

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

Функцию пишет производитель используемого типа. Ну да, допустим. Добавили пару строчек кода и лишнее знание о типе.

а второй пункт как обойти?

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

Да. Как в зависимости от типа определить, можно ли memcpy вызывать, или надо честно проходить весь массив и копировать

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

Ты только узнал про собирательные числительные? Или когда тебе говорят «подожди пару секунд», то ты засекаешь 2 секунды?

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

Чисто так, для показательной порки:

	GData *data = NULL;
	gpointer ptr;

	typedef struct {
		gchar* nick;
		gint id;
	} person;

	person Prs = {g_strdup ("Dendy"), 38};

	g_datalist_set_data (&data, Prs.nick, &Prs);

	ptr = g_datalist_get_data (&data, Prs.nick);

	g_print ("%s: %d\n", ((person *) ptr)->nick, ((person *) ptr)->id);

А теперь дуй учиться.

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

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

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от ananas

> а при чем тут тип? memmove + sizeof в зубы, и вперед

Ага. А если в объекте есть внутренние ссылки - кто их перераспределять будет? Господ Бог?

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

Посмотри, как реализован GArray. Увидишь и как там размер элементов разруливается.

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

> Поэтому никакой сложности в ее реализации нет.

В реализации нет. А вот в вызове есть - ее надо указывать явно.

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

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

>>Мужик, ну ты даешь. А где блин хоть какая нить проверка типа?

Зачем она здесь? Или ты думаешь, что через какой-то эфир в моем списке поменяется тип хранимых данных?

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