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

★★★★★

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

ну нельзя без допиливания написать

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

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

я поимел пару неприятных недель дружбы бустовых пул-аллокаторов со сложными stl-based структурами данных

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

>а вот то что между ними невозможны никакие операции - это Вы крепко гоните

Конкатенация? Сравнение? Копирование?

Вы хотите сказать что в данном случае не знаете как сделать конкатенацию сравнение и копирование? я Вас правильно понял?

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

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

Я уже упоминал о недостаточном опыте? Заглянь в исходники glibc и обнаружь следующие вещи:

1. Блок памяти, возвращаемый malloc'ом всегда выровнен по границе 16 байт. Вывод: при выделении трех блоков памяти объем неиспользуемой памяти может достигать 45 байт (средняя длина ника менее 10 ASCII символов, кстати), тогда как при выделении одного блока памяти «потеряются» максимум 15 байт.

2. 8-байтный заголовок блока памяти в куче (8 байт против 24); на 64-битной архитектуре вроде оверхед еще больше.

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

4. Вызов malloc даже близко не бесплатный, что бы там ни писали в современных книжках (а уж как он загаживает наши любимые кэши!).

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

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

> В таких случаях как раз и приходится паковать, выигрывая абсолютно по всем показателям: скорость, фрагментация, объем занимаемой памяти

и это можно сделать и на С++ - если будет именно такая задача, это не проблема самого языка, это проблема как его используют, точно также можно взять пример мужика-2 с glib, когда у него решение на С оказалось медленнее решения на С++ ( хотя он с этим не согласен - но у всех, кроме него так получилось )

в памяти нужно уместить пару сотен миллионов небольших записей


обычно для таких задач применяют СУБД по многим причинам

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

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

А, ты в книжке прочитал, что оно не нужно?

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

Ты не поверишь, но использование apr_pool_t в C — это просто сказка. Удобно и эффективно. Плюсовые аллокаторы нервно курят в сторонке.

Вы хотите сказать что в данном случае не знаете как сделать конкатенацию сравнение и копирование?

У тебя есть pooled_string (с быстрым стековым аллокатором для хранения временных данных) и std::string (для хранения долгоживущих данных). Вопрос №1: что должен возвращать operator+(const pooled_string &, const std::string&)? Вопрос №2: как придется извратиться для создания pooled_string& operator=(const std::string&)? Вопрос №3: после всего этого ужаса появляется вопрос: возможно ли на C++ эффективно писать что-то кроме лабораторных и «бенчмарков для лора»? Вопрос №4: Почему эффективный C++ в разы костылявей эффективного C?

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

>и это можно сделать

Укажи путь, как это можно сделать в C++? Отказаться от плюсовых структур данных?

обычно для таких задач применяют СУБД по многим причинам

Ты университет-то хоть закончил? СУБД применяют, потому что это «дешево и сердито», но использовать реляционную СУБД (зрелых объектных вроде пока нет, а если и есть, то они потормознее реляционных будут) для хранения in-memory cache... Премию Дарвина за такие решения давать следует.

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

> Вопрос №3: после всего этого ужаса появляется вопрос: возможно ли на C++ эффективно писать что-то кроме лабораторных и «бенчмарков для лора»?

этот «ужас» придуман на ровном месте :) везде используют std::string

Вопрос №4: Почему эффективный C++ в разы костылявей эффективного C?


если самому не городить костыли - их не будет

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

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

Я уже упоминал о недостаточном опыте? Заглянь в исходники glibc и обнаружь следующие вещи:

1. Блок памяти, возвращаемый malloc'ом всегда выровнен по границе 16 байт. Вывод: при выделении трех блоков памяти объем неиспользуемой памяти может достигать 45 байт (средняя длина ника менее 10 ASCII символов, кстати), тогда как при выделении одного блока памяти «потеряются» максимум 15 байт.

2. 8-байтный заголовок блока памяти в куче (8 байт против 24); на 64-битной архитектуре вроде оверхед еще больше.

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

4. Вызов malloc даже близко не бесплатный, что бы там ни писали в современных книжках (а уж как он загаживает наши любимые кэши!).

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

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

в-третьих, запилите уже custom allocator и будьте счастливы, пусть он все эти вещи разруливает

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

о да, подсчёт ссылок позволяет поиметь много крепкого «сексу» в многопоточных средах :)

Вы всё время думаете только о своих узкозаточенных задачах, между тем обсуждаются обобщённые контейнеры, чувствуете где скользко?

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

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

> Укажи путь, как это можно сделать в C++? Отказаться от плюсовых структур данных?

опять же в тех СУБД данные хранятся( кроме блобов ) одной строкой

Ты университет-то хоть закончил? СУБД применяют, потому что это «дешево и сердито», но использовать реляционную СУБД (зрелых объектных вроде пока нет, а если и есть, то они потормознее реляционных будут) для хранения in-memory cache... Премию Дарвина за такие решения давать следует.


ты идиот, уж извини :)

1. БД прекрасно может быть создана в ОЗУ
2. для того, чтоб пройтись по полю можно просто инкременитить указатель на уже известное число, а тебе надо будет вычитывать постоянно смещения

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

> а тебе надо будет вычитывать постоянно смещения

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

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

или в твоем варианте данные не только менять, но и читать не надо? :)

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

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

А, ты в книжке прочитал, что оно не нужно?

раз уж начали играть в вопросы: Вы всегда только книжки читаете, головой думать - не?

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

Ты не поверишь, но использование apr_pool_t в C — это просто сказка. Удобно и эффективно. Плюсовые аллокаторы нервно курят в сторонке.

не поверю :) но вовсе не потому что apr_pool_t - это плохо, а потому что Вы не учитываете оверхед валящийся Вам на голову как только Вы начинаете использовать чистый си

тебя есть pooled_string (с быстрым стековым аллокатором для хранения временных данных) и std::string (для хранения долгоживущих данных).

допустим

№1: что должен возвращать operator+(const pooled_string &, const std::string&)?

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

Вопрос №2: как придется извратиться для создания pooled_string& operator=(const std::string&)?

а в чём проблема? используется POD (char), размер типа данных у обоих контейнеров одинаковый, проверяете чтобы места хватило и memcpy :) *SURPRISE*

Вопрос №3: после всего этого ужаса появляется вопрос: возможно ли на C++ эффективно писать что-то кроме лабораторных и «бенчмарков для лора»?

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

вполне возможно, но нужен опыт, впрочем как и в любом другом деле

Вопрос №4: Почему эффективный C++ в разы костылявей эффективного C?

толстая провокация флейма

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

>во-первых, Вы то говорите об экономии памяти, то о скорости

Я говорю о них вместе. Экономится и память, и такты процессора.

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

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

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

Да в лабораторных можно вообще не париться!

в-третьих, запилите уже custom allocator и будьте счастливы, пусть он все эти вещи разруливает

Я выше уже описывал многочисленные проблемы с пользовательскими аллокаторами. Если еще не долшло, поясню на пальцах: существование сторонних cpp-библиотек, которые хотя std::string сильно усложняет жизнь. Так понятнее?

между тем обсуждаются обобщённые контейнеры

std::string назвать обобщенным контейнером язык не поворачивается, а речь сейчас идет именно о нем.

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

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

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

> Не вижу необходимости доказывать очевидный факт, что один вызов malloc быстрее, чем три вызова malloc.

а тот факт, что strlen для каждого поля/строки при чтении/добавлении - это не очень быстро, тоже очевидно? а то что вариант на С++ сразу позволяет изменить данные, а не писать костыль?

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

>1. БД прекрасно может быть создана в ОЗУ

Огромные накладные расходы! Речь идет о данных, которые в ОЗУ еле-еле помещаются с извратами, а ты захотел там реляционную СУБД (небось еще и с журналированием) развернуть. И кто после этого идиот?

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

Что значит «пройтись по полю»? Какие указатели? Намекаешь на то, что у меня структура данных не фиксированного размера? Я в курсе. И я прекрасно знаю, что ее нельзя в struct Person[] уложить. Зато она прекрасно укладывается в связанные списки, деревья и прочие сложные структуры данных, где каждый элемент хранится отдельно.

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

>а тот факт, что strlen для каждого поля/строки при чтении/добавлении - это не очень быстро, тоже очевидно?

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

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

Ох лол! Ни в одном из приведенных вариантов кода я не увидел изменения данных. Везде use-case это «заполняем, потом ищем». Неужели непонятно, что и в жизни все также?

Кстати, у меня вопрос: а тебе очевидно, что в плюсовом варианте строка с ником дублируется, и, скажем, в STLPort это двойной оверхед по памяти?

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

>тебе при обходе записей придется каждый раз для каждой strlen вызывать

Зачем?! С чего ты взял, что записи лежат в линейном массиве?

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

> речь идет о данных, которые в ОЗУ еле-еле помещаются с извратами

100 млн записей? так там и до креша недалеко ;) а умная СУБД сама сбросит часть данных на диск, если свободной памяти не останется

Что значит «пройтись по полю»?


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

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


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

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

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

один раз или два раза - все равно, да?

Кстати, у меня вопрос: а тебе очевидно, что в плюсовом варианте строка с ником дублируется, и, скажем, в STLPort это двойной оверхед по памяти?


это ты про какой именно вариант? скопипасть плз - бо их много было

Зачем?! С чего ты взял, что записи лежат в линейном массиве?


как я и думал - появилось новое условие :) и это не отменяет тот факт, что у тебя не хранится смещение и чтоб получить вторую строку + ее размер надо вызвать два раза strlen

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

>не поверю :) но вовсе не потому что apr_pool_t - это плохо, а потому что Вы не учитываете оверхед валящийся Вам на голову как только Вы начинаете использовать чистый си

Покажи мне оверхед! Я пока вижу только бесконечные плюсовые оверхеды на копирование результата (man operator+).

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

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

используется POD (char), размер типа данных у обоих контейнеров одинаковый, проверяете чтобы места хватило и memcpy :)

Ты правда такой непонятливый чтоли? Я тебе говорю, что такой operator= ты никак не добавишь, остается только наследоваться. А ведь сначала казалось, что меняется только параметр шаблона.

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

Пока непонимание и недостаток опыта здесь демонстрируешь ты. Мне уже начинает надоедать объяснять прописные истины.

толстая провокация флейма

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

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

>100 млн записей? так там и до креша недалеко ;) а умная СУБД сама сбросит часть данных на диск, если свободной памяти не останется

Ок, эту ветку дискуссии закрыли в силу твоей недостаточной ментальной зрелости и святой веры в реляционные СУБД.

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

Смотри-ка, до тебя дошло, что данные хранят для выборки. Значит еще пара страниц — и ты поймешь, что линейный массив для выборки вариант весьма стремный.

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

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

только вдобавок можно еще и запросы для данных строить

:D:D:D Ага, на эс-кью-эль :D:D:D

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

>и это не отменяет тот факт, что у тебя не хранится смещение и чтоб получить вторую строку + ее размер надо вызвать два раза strlen

Мальчик, ты совсем не соображаешь?!

struct Person {
  char *nick;
  char name[0];
}
....
struct Person *p = make_person("ahonimous", "Балбес");

printf("%s - %s\n", p->nick, p->name);

Где здесь strlen при обращении к полю?!

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

> Ок, эту ветку дискуссии закрыли в силу твоей недостаточной ментальной зрелости и святой веры в реляционные СУБД.

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

Значит еще пара страниц — и ты поймешь, что линейный массив для выборки вариант весьма стремный.


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

:D:D:D Ага, на эс-кью-эль :D:D:D


как один из множества вариантов - да

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

> Где здесь strlen при обращении к полю?!

да - зевнул, не переживай только так сильно

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

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

На пентиум-двести-эм-эм-икс точно нельзя. А на боевой машине, в которую воткнули 8/16/32 гигабайта RAM специально для того, чтобы все поместилось, еще как можно! Погугли по слову memcache чтоли.

я тебе уже на этой могу про индексы рассказать

Ок, как физически выглядит индекс?

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

> А на боевой машине, в которую воткнули 8/16/32 гигабайта RAM специально для того, чтобы все поместилось, еще как можно!

а все начиналось с адресной книги :) а получили «боевую машину» с 8/16/32 гигабайт RAМ и все эти 32Гб под завязку забиты статичными данными

Ок, как физически выглядит индекс?


в общем случае набор «указателей» на RecID + собс-но описание критерия

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

>а все начиналось с адресной книги :) а получили «боевую машину» с 8/16/32 гигабайт RAМ и все эти 32Гб под завязку забиты статичными данными

А что здесь удивительного?

в общем случае набор «указателей» на RecID + собс-но описание критерия

Скажи мне, не видишь ли ты здесь чего-то лишнего: std::map<std::string,Person>?

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

Все ваши вопросы - это ваши сексуальный фантазии

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

>> да переопредели ты new, и не мучайся

это плохое решение, которое чревато проблемами

Чем чем черевато? Почему?

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

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

Строки хранятся в одном блоке памяти вместе со структурой. Попробуй изобразить такое с std::string/QString.

Изобрази на конкретном примере свои мысли. QT знаю плохо (но тут есть «монстры» по этому делу), а stl пожалуйста. Посмотрим может ты и прав?)

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

> Опять теоретики разбушевались?

Яви нам код!) Один уже явил, но как-то скис не по-делу в итоге )))

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

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

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

Да... Во кодище. Во сткрутур. Во зависимостей. А потом где нить лишний free и 50 лет на отладку при загрузке 10000000 записей

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

> Щазз, все бросил, побежал школьные лабораторные писать.

Конечно, кому охота облажаться на публике. У Мужика то еще зачтется, если он скажет «ХЗ, чё такое, у меня все ништяк»!) Тебя же по полной программе осудят и ...)))

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

Пожалуйста:

#include <map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static unsigned int bytes;
static unsigned int blocks;
extern "C" void* __libc_malloc(size_t size);
extern "C" void* malloc(size_t size)
{
    bytes += size;
    blocks++;
    return __libc_malloc(size);
}
struct person {
    const char *name;
    const char nick[0];
};

struct person* make_person(const char *nick, const char *name)
{
    unsigned nick_l = strlen(nick) + 1, name_l = strlen(name) + 1;
    struct person *p = (struct person*)malloc(sizeof(*p) + nick_l + name_l);
    p->name = (char*)p + sizeof(*p) + nick_l;
    memcpy((char*)p->name, name, name_l);
    memcpy((char*)p->nick, nick, nick_l);
    return p;
}

struct Person {
    std::string nick;
    std::string name;
    Person(const char *nick, const char *name) : nick(nick), name(name) {}
};

#define NAME "name"
#define NICK "nick"

int main()
{
    unsigned actual;
    bytes = blocks = 0;
    {
        Person p(NICK, NAME);
        actual = sizeof(p) + sizeof(NICK) + sizeof(NAME);
    }
    printf("C++: allocated %4u in %2u blocks, actual: %4u overhead: %4u\n", bytes, blocks, actual, bytes - actual);
    bytes = blocks = 0;
    person *p = make_person(NICK, NAME);
    actual = sizeof(*p) + sizeof(NICK) + sizeof(NAME);
    printf("C:   allocated %4u in %2u blocks, actual: %4u overhead: %4u\n", bytes, blocks, actual, bytes - actual);
    free(p);
    return 0;
}
linuxfan
()
Ответ на: комментарий от namezys

> Да не напишут они на Си что нить эффективнее хорошего С++ больше лаборотоки студенческой

Мне кажется это из-за того, что кто-то путает STL с C++.

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

А. Не. Некорм. Человек пытается показать всем то, что и так все знают - в его задаче стандартными средствами с его требованиями ничего не сделать

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

> А что здесь удивительного?

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

Скажи мне, не видишь ли ты здесь чего-то лишнего: std::map<std::string,Person>?


варианты:
- убрать поле name из Person
- хранить все не в map, а в отсортированном векторе - пожалуй лучшее и самое быстрое решение для статичных данных
- хранить все в векторе, но рядом держать подобие индекса ( который создается простым qsort ) - хуже предыдущего, но можно охватить все поля - строки, числа, даты и т.п.

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

> Я согласен с тем, что на такие трюки пофиг, если ты делаешь адресную книгу деревни Старые Васюки на 4 гигабайтах оперативки. Но бывают в жизни такие ситуации

Я не раз тут уже говорил, что если вдруг «военная железка» и в системе нет С++ и ты более того её сам пишешь, то Си с его ООП кастылями вполне вкусно. А в других случаях лучше С++. Ты же тут заявлял, что типо тебе не проблем наваять своих ООП костылей, лижбо это было чистый Си )))

Я понимаю, что Линукс был и пишется на Си. Но ты уподобляешься совковым фанатекам ) которые заявляли (в лице Маяковского) «Я русский бы выучил только за то, что на нем разговаривал Ленин» )))

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

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

вот продает себя задорого

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

> Чем чем черевато? Почему?

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

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

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

Я понял его в том посте где он явил нам образец своего кода. Да на С++ такое и никому в голову не придет (хотя наверно можно извратиться если сильно постараться), подсчитать размер объект и целиком его сразу разместить в памяти, а членом присваивать смещение. ОК, если это ридонли объект может это будет и быстрее, а если в его примере захотят изменить имя или ник, тем более они паблик ) И что весь его код уйдет в топку, Нет?)

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

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

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

> И что весь его код уйдет в топку, Нет?)

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

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

>> И что весь его код уйдет в топку, Нет?)

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

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

И я просто не пойму, чего этот чел тут пропагандировал?)

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

> можно же переопределить для класса

для Person и string - да, и можно даже просто написать «new(p) Person», а как ты так заставишь буффер строки указывать на эту единую область памяти?

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