Здравствуйте, Erop, Вы писали:
E>Здравствуйте, gid_vvp, Вы писали:
_>>пишем C++ обёртки над этим C style API E>Ну это и есть так называемое "совсем не уменьшается производительность труда" и "зачем писать свой велосипед, если есть STL"
E>Но это всё лирика. Вот есть LISTBOX. Наверное он довольно известен. На всяк случай скажу, что там на элемент можно задать 32 бита данных. E>И что же мы пишем, чтобы запихнуть туда итератор?
Ну итератор туда запихивать не стоит... он может инвалидироаться в самый неподходящий момент, лучше там хранить ID из map или hashmap
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Реальный способ тут только один — уситься пользоваться беззнаковыми типами как можно раньше. 99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях.
Да ну — а java? Зачем они вообще беззнаковые? К томуже С никак не контролирует их. Пытался напмсать тут кое что на чистом С, потом плюнул и заменил одной командой __asm JC — даже не помню какие там типы были, рояли не играло
Здравствуйте, gid_vvp, Вы писали:
E>>Но это всё лирика. Вот есть LISTBOX. Наверное он довольно известен. На всяк случай скажу, что там на элемент можно задать 32 бита данных. E>>И что же мы пишем, чтобы запихнуть туда итератор?
_>Ну итератор туда запихивать не стоит... он может инвалидироаться в самый неподходящий момент, лучше там хранить ID из map или hashmap
О! Теперь я знаю, почему вычислительная мощность компьютеров растет, а скорость программ падает!
Мне еще где-то здесь предлагали создать объект с помощью new, поместить туда итератор,указатель на созданный объект запихнуть в DATA, а при уничтожении Listbox'a проходить по всем элементам и удалять память из под итераторов.
Мое ИМХО: ООП это отличная парадигма, существенно продвинувшая программирование, но это не значит что все переменные в программе должны быть активными объектами. Программа превращается в разбегающийся в разные стороны муравейник.
Объектами стоит делать то, что действительно является объектами в предметной области, или то что является объектом в системе, например объекты GUI.
Окно, кнопка — безусловно объект. Структуры данных (контейнеры) список, дерево, таблица — однозначно объекты. Но зачем делать объектом маленький итератор? Не перебор ли это?
Другими словами: объектом может быть то что самодостаточно. Контейнеру никто не нужен для существования. Итератору нужен контейнер — без него итератор бессмысленен, следовательно он лишь часть, примочка к контейнеру, а не самостоятельный объект. В этом смысле STL — что-то вроде кривой попытки заменить сишные указатели. Я вообще считаю перегрузку операций (в особенности операций доступа * ->) не очень хорошей вещью и делаю только перегрузку копирования (конструктор копирования и оператор присваивания) да и то по необходимости.
Здравствуйте, Пётр Седов, Вы писали:
E>>Странно. В известных мне операционках, обычно можно отматать столько стэка, сколько надо... E>>Пишешь нужное число в заголовок exeшника и всё... ПС>Зачем patch-ить exe-файл? Серьёзный компилятор позволяет указать размер stack-а главного thread-а.
Конечно то, что ты пишешь, правда, но я и не предлагал патчить заголовок из hexeditor
Вот, скажем, если ты хочешь сделать приложение консольным, ты тоже будешь думать, что надо экзешник патчить, а не опцию линкера менять?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Smal, Вы писали:
S>Здравствуйте, all.
S>Долго пытался не влезать в эту дискуссию, но все же попытаюсь изложить собственное мнение. <...>
Не стоит вместо аргументов чем хороша STL заявлять, что те кто её критикует или не разобрались, или слишком консервативны и.т.п.
S>В действительности, даже такие структуры как std::map<string> достаточно быстры,
"За такие структуры у нас увольняют." (c) мой
S>Остается только надеяться, что такое положение дел положительно скажется на развитии стандартной библиотеки.
Она давно уже не развивается. Фактически, с её первого появления не была проделана необходимая работа над ошибками.
По сути STL как проект мертва.
Здравствуйте, ., Вы писали: >> Пишешь нужное число в заголовок exeшника и всё... .>Ну это аналогично вызову reserve с большим числом прозапас (или специальному аллокатору с фиксированным размером).
Аналогия – вещь скользкая. И там, и там слово «reserve», но есть разница.
VirtualAlloc(NULL, 1024 * 1024, MEM_RESERVE, PAGE_READWRITE) резервирует диапазон виртуальных адресов. Поначалу эти виртуальные адреса не подкреплены физической памятью (физическая память – это оперативная память или swap file). Только по мере того, как stack растёт вглубь, виртуальные страницы отображаются на физические страницы (страница (page) – кусок памяти размером 4 KB). Поэтому в stack-е количество «лишней» физической памяти <= 4 KB. Выход за рамки резерва смертелен: возбуждается структурное исключение Win32 и программа, скорее всего, аварийно завершается.
vector<byte>::reserve(1024 * 1024) (и string::reserve(1024 * 1024)) запрашивает мегабайт физической памяти. Если используется малая доля резерва, то будет много «лишней» физической памяти (которая недоступна остальным процессам). Выход за рамки резерва влечёт realloc + переезд элементов на новое место жительства.
Здравствуйте, gid_vvp, Вы писали:
E>>>Там идея такая, что можно преобразовывать строки в числа и взад. Довольно легко и прямо. LM>>boost::lexical_cast E>>>При этом они там строки короче чего-то вообще не аллокируют никогда. LM>>MS реализация std::string _>т.е. ты видел это ? (PowerPlant)
Нет, я видел boost::lexical_cast и MS реализация std::string
Здравствуйте, x-code, Вы писали:
XC>Здравствуйте, gid_vvp, Вы писали:
E>>>Но это всё лирика. Вот есть LISTBOX. Наверное он довольно известен. На всяк случай скажу, что там на элемент можно задать 32 бита данных. E>>>И что же мы пишем, чтобы запихнуть туда итератор?
_>>Ну итератор туда запихивать не стоит... он может инвалидироаться в самый неподходящий момент, лучше там хранить ID из map или hashmap
XC>О! Теперь я знаю, почему вычислительная мощность компьютеров растет, а скорость программ падает!
Произведи замеры производительности и тогда говори о скорости.
Это во первых, во вторых мешать UI и логику очень плохая идея, ну не должны гуишные элементы содержать в себе логику.
XC>Мне еще где-то здесь предлагали создать объект с помощью new, поместить туда итератор,указатель на созданный объект запихнуть в DATA, а при уничтожении Listbox'a проходить по всем элементам и удалять память из под итераторов.
XC>Мое ИМХО: ООП это отличная парадигма, существенно продвинувшая программирование, но это не значит что все переменные в программе должны быть активными объектами. Программа превращается в разбегающийся в разные стороны муравейник. XC>Объектами стоит делать то, что действительно является объектами в предметной области, или то что является объектом в системе, например объекты GUI. XC>Окно, кнопка — безусловно объект. Структуры данных (контейнеры) список, дерево, таблица — однозначно объекты. Но зачем делать объектом маленький итератор? Не перебор ли это? XC>Другими словами: объектом может быть то что самодостаточно. Контейнеру никто не нужен для существования. Итератору нужен контейнер — без него итератор бессмысленен, следовательно он лишь часть, примочка к контейнеру, а не самостоятельный объект. В этом смысле STL — что-то вроде кривой попытки заменить сишные указатели. Я вообще считаю перегрузку операций (в особенности операций доступа * ->) не очень хорошей вещью и делаю только перегрузку копирования (конструктор копирования и оператор присваивания) да и то по необходимости.
Это ты кому отвечаешь? Тем кто рекомендовал создавать итераторы на куче?
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, Аноним, Вы писали:
А>>2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция дорога.
АТ>Это опасность "по невнимательности". Таких опасностей в С++ много и недостаками они в рамках идеологии С++ считаются не должны.
Тут вопрос глубже на самом деле. А зачем вообще копировать контейнеры? Это требуется весьма нечасто. Соотвественно, ничего страшного нет в запрете на копирование и использовании специального метода clone для создание копии.
Копирование стандартных контейнеров разрешено на самом деле потому, что иначе их нельзя было бы хранить в контейнерах.
Иными словами один фундаментальный дефект STL -- неспособность контейнеров хранить некопирабельные типы приводит к другому -- разрешению неявного копирования контейнеров.
АТ>Реальный способ тут только один — уситься пользоваться беззнаковыми типами как можно раньше. 99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях.
По моему, это слишком сильное утверждение.
struct Point
{
int x,y; // здесь вряд ли беззнаковый тип уместен
};
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Это опасность "по невнимательности". Таких опасностей в С++ много и недостаками они в рамках идеологии С++ считаются не должны. АТ>Ошибки при использовании беззнаковых типов (в т.ч. в примерах ниже) обусловлены обычно 1) невнимательностью и 2) неоправданным смешением знаковых и беззнаковых типов. По этой причине, аргументами их считать сложно. АТ>Реальный способ тут только один — учиться пользоваться беззнаковыми типами как можно раньше. АТ>"Страховочное" использование знаковых типов допустимо для начинающего программиста, но не более.
Это первая группа комментов. Если коротко, то так: "Увольте всех невнимательных программистов и напишите, наконец, прекрасную программу "Hellow World!" в одинчку. Внимательно, правильно и без этих всех глупых и труднообнаружимых ошибок!
Так?
Интересно, как ты относишься к private членам классов? Они ведь тоже с невнимательностью борятся. Просто надо писать и внимательно нтарии и не вызывать что попало где не надо
АТ>Слабый и странный "минус". АТ>Неочевидно. Если и минус, то очень слабый. АТ>По-моему это вопрос качества реализации. Нет? АТ>Нет. Не вижу в этом минуса. А придумать ситуацию, когда это неудобно можно всегда. АТ>В общес случае — нельзя. Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса".
Вторая большая группа "возражений". В переводе на русский: "Я не понял или не знаю что сказать"
Особенно прикольно последнее "возрадение". Интересно бы узнать плюсы такого ограничения, например
На этом я хотел уже закончить, но таки не могу НУ КАК МОЖНО ТАК ДУМАТЬ?
АТ>...Использование беззнакого типа вполне оправдано, ибо соответствует он заведомо неотрицательному значению. В данном случае наблюдается следование правилу "всегда использовать в программе только беззнаковые типы, кроме тех мест, где необходим знаковый тип", что более чем похвально.
Конечно более чем похвально. Так как повышает зарплаты тех, кто так делает, в виду малого их числа
А что делать с криворукими сотрудниками, которые так не делают надо смотреть чуть выше в этом посте, Да?
АТ>99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях.
А вот это совсем интересно. Всё-таки чем так сильно C++ отличается от остальных процедурных и ООП языков? Почему-то в остальных вполне получается писать хорошие программы вообще без использования беззнаковых целых, и только на C++ 99% должны быть беззнаковыми?
Ещё интересно, как ты обходишься без типа unsigned double. Тяжело наверное?..
Выводы:
А выводы-то всё те же. Что мы видим с вами?
А вилим мы то, что STL очень заточен под идеологически правильные споры, под написание сверхкорректного кода каких-то мифических прекрасных сэмплов, каким-то не менее мифическими сверхвысококвалифицированными, сверхвнимательными и сверхаккуратными программистами.
Либо для обучения этих спецов (конечно, ещё Суворов говаривал, что в учении должно быть тяжело
А для тех, кто хочет что-то такое программировать в практических целях, например, чтобы продать, STL не выгодный какой-то. Так как далёк он от практики. Вопросы, которые важны для кого-то, кто пишет программы на практике, не являются минусами или являются особенностями реализации (ну вот есть у тебя такая особенность. А делать-то чего? , как будто реализация не может угробить и прекрасную идею ), операции со строками не важны, важно, чтобы можно было родить строку из любых объектов. Напрмиер из умныз указателей на открытые файлы, скажем, ну и так далее и тому подобное
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Аноним, Вы писали: А>… MFC 4.2 …
Я ошибся. На самом деле вместе с MSVC6 поставляется MFC 6.0 (хотя файл называется mfc42.dll + варианты). Во-первых, это написано в MSDN (здесь):
ATL and MFC Version Numbers
…
The versions of MFC shipped with Visual C++ as listed in the following table.
MFC version
Visual C++ version
1.0
Microsoft C/C++ 7.0
2.0
Visual C++ 1.0
2.5
Visual C++ 1.5
3.0
Visual C++ 2.0
3.1
Visual C++ 2.1
3.2
Visual C++ 2.2
4.0
Visual C++ 4.0
4.1
Visual C++ 4.1
4.2
Visual C++ 4.2
4.21 (mfc42.dll)
Visual C++ 5.0
6.0 (mfc42.dll)
Visual C++ 6.0
7.0 (mfc70.dll)
Visual C++ .NET 2002
7.1 (mfc71.dll)
Visual C++ .NET 2003
8.0 (mfc80.dll)
Visual C++ 2005
Во-вторых, это написано в afxver_.h:
#define _MFC_VER 0x0600 // Microsoft Foundation Classes version 6.00, VC++ 6.0
Поэтому вместо «MFC 4.2» надо читать «MFC 6.0».
Извините, ввёл в заблуждение.
S>>В действительности, даже такие структуры как std::map<string> достаточно быстры, Ш>"За такие структуры у нас увольняют." (c) мой
А можно по подробнее?
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[5]: Возвращаясь к украинской теме: Сколько же точек над i
Здравствуйте, x-code, Вы писали:
XC>Здравствуйте, gid_vvp, Вы писали:
E>>>Но это всё лирика. Вот есть LISTBOX. Наверное он довольно известен. На всяк случай скажу, что там на элемент можно задать 32 бита данных. E>>>И что же мы пишем, чтобы запихнуть туда итератор?
_>>Ну итератор туда запихивать не стоит... он может инвалидироаться в самый неподходящий момент, лучше там хранить ID из map или hashmap
XC>О! Теперь я знаю, почему вычислительная мощность компьютеров растет, а скорость программ падает!
XC>Мне еще где-то здесь предлагали создать объект с помощью new, поместить туда итератор,указатель на созданный объект запихнуть в DATA, а при уничтожении Listbox'a проходить по всем элементам и удалять память из под итераторов.
А что программирование на ГУИ заканчивается? Тут вообще лучше не С++ использовать, но раз уж пришлось, то используй то средство, что подходит лучше в чем проблема? СТЛ от этого хуже на стала.
XC>Мое ИМХО: ООП это отличная парадигма, существенно продвинувшая программирование, но это не значит что все переменные в программе должны быть активными объектами. Программа превращается в разбегающийся в разные стороны муравейник. XC>Объектами стоит делать то, что действительно является объектами в предметной области, или то что является объектом в системе, например объекты GUI. XC>Окно, кнопка — безусловно объект. Структуры данных (контейнеры) список, дерево, таблица — однозначно объекты. Но зачем делать объектом маленький итератор? Не перебор ли это? XC>Другими словами: объектом может быть то что самодостаточно. Контейнеру никто не нужен для существования. Итератору нужен контейнер — без него итератор бессмысленен, следовательно он лишь часть, примочка к контейнеру, а не самостоятельный объект. В этом смысле STL — что-то вроде кривой попытки заменить сишные указатели. Я вообще считаю перегрузку операций (в особенности операций доступа * ->) не очень хорошей вещью и делаю только перегрузку копирования (конструктор копирования и оператор присваивания) да и то по необходимости.
Вообще это все слой абстракции м-ду программистом и низкоуровневыми средствами (голые указатели, управление памятью). Не забываем, что С++ имеет совместимость с С. А в чем кривость этой попытки? Итератор — это тот же указатель по смыслу, только ограничен семантикой перебора, разыменования. Умный указатель это новая семантика которую уже внес С++ — семантика владения. ИМХО очень даже хорошо, что они разделены.
ЗЫ Кстати wxWidgets хотя и одна из самых древних ГУИ библиотек, гораздо более совместима с СТЛ, чем тот же МФЦ, правда МФЦ уже никто не развивает, что не может не радовать .
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Здравствуйте, Tom, Вы писали:
S>>>В действительности, даже такие структуры как std::map<string> достаточно быстры, Ш>>"За такие структуры у нас увольняют." (c) мой Tom>А можно по подробнее?
Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья.
Кроме того, string может иметь дорогой оператор копирования. Именно поэтому его нельзя использовать для работы с большим массивом строк.
Плюс фрагментация памяти.
Шахтер wrote:
> Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья.
Просто hash_map нестандарна...
> Кроме того, string может иметь дорогой оператор копирования. Именно > поэтому его нельзя использовать для работы с большим массивом строк. > Плюс фрагментация памяти.
Тут же string в качестве ключа используется, копирование при помещении в map всё равно будет. Какая разница?
Разница только в алгоритме поиска по ключу — пополамным делением отсортированной структуры или через вычисление хеша и
поиска по хешу.
Со строками до нескольких килобайт думаю большой разницы не будет. memcmp работает очень быстро.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Андрей Тарасевич, Вы писали:
А>>2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция дорога. АТ>Это опасность "по невнимательности". Таких опасностей в С++ много и недостаками они в рамках идеологии С++ считаются не должны.
«Недостаток» – жёсткое слово. Я бы сказал мягче: спорный вопрос. Для string-а неявное копирование желательно, так же как неявное преобразование строкового литерала в string.
А>>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы. АТ>Это неверно. В STL-контейнерах никак не используется 'size_t'. Используется же там контейнерно-зависимый беззнаковый тип 'size_type'.
Реализации STL, которые я видел, по умолчанию используют именно size_t.
Вместо «заведомо неотрицательного» string::npos можно было придумать что-нибудь вроде Boost.Optional, но «-1» проще.
АТ>В данном случае наблюдается следование правилу "всегда использовать в программе только беззнаковые типы, кроме тех мест, где необходим знаковый тип", что более чем похвально. АТ>Ошибки при использовании беззнаковых типов (в т.ч. в примерах ниже) обусловлены обычно 1) невнимательностью и 2) неоправданным смешением знаковых и беззнаковых типов. По этой причине, аргументами их считать сложно. А>>Сам он всячески призывает программиста использовать int. АТ>В этом Страуструп не столько "не прав", сколько допускает черезмерное упрощение, ориентируясь на начинающего программиста (его книга изобилует такими упрощениями). Это лишь вопрос подходов к обучению: учиться ли правильному использованию беззнаковых типов с самого начала, или все таки отложить на потом. Страуструп считает, что лучше отложить. Многие считают что лучше сразу.
Беззнаковые типы и беззнаковая арифметика – разные вещи. Беззнаковая арифметика (особенно беззнаковое вычитание) – низкоуровневая техника и грабли. Её стоит использовать только в исключительных случаях. Подробнее: беззнаковый спор
.
А>>Какое отношение size_t имеет к array-based контейнерам (vector, string), ещё понятно: в языках C/C++ длина/индекс массива выражаются типом size_t. Какое отношение size_t имеет к node-based контейнерам (list, map), непонятно совсем. В 90-ые годы (время проектирования STL), когда ещё живы были 16-битные платформы, использование size_t было оправдано. Сейчас это источник тонких ошибок. АТ>Это утверждение построено на неверном предположении, что используется именно тип 'size_t'. На самом деле же никакого 'size_t' там и близко нет. Не надо путать 'size_t' с 'container<>::size_type'.
Реализации STL, которые я видел, по умолчанию используют именно size_t. Смотрите выше.
А>>"Проблему size_t" можно решить несколькими способами: АТ>Реальный способ тут только один — уситься пользоваться беззнаковыми типами как можно раньше. 99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях. АТ>"Страховочное" использование знаковых типов допустимо для начинающего программиста, но не более.
Про беззнаковую арифметику смотрите выше.
А>>5. Нельзя получить итератор по указателю на элемент контейнера за константное время. АТ>В общес случае — нельзя.
Да, я писал об этом здесь
A_A>А кто сказал, что это возможно для любых итераторов и любых контейнеров?
Никто. Но для некоторых возможно:
…
АТ>Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса".
Вполне возможен такой вариант. Все контейнеры имеют метод iterator_from_pointer. В некоторых случаях iterator_from_pointer работает за константное время (например, list::iterator_from_pointer в Release-конфигурации). В некоторых случаях iterator_from_pointer работает за время O(container.size()) (например, deque::iterator_from_pointer, list::iterator_from_pointer в Debug-конфигурации).
MaximE пишет об этом здесь
(он назвал «derive_iterator»).
А>>6. Вместо метода empty удобнее был бы метод с позитивным смыслом, например has_elems (возвращает true <=> в контейнере есть хотя бы один элемент). АТ>Неочевидно. Если и минус, то очень слабый.
Чем меньше отрицаний, тем понятнее код. Например, вместо:
while (!Queue.empty())
{
...
}
было бы лучше писать:
while (Queue.has_elems())
{
...
}
Чтобы писать понятный код, нужны методы has_elems и is_empty (например, «assert(Queue.is_empty())»).
Функции вроде char_traits::not_eof производят странное впечатление.
А>>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне. АТ>Слабый и странный "минус".
Иногда нужно снять константность с итератора. Скотт Мейерс в книге «Эффективное использование STL»
пишет (совет 27): «Используйте distance и advance для преобразования const_iterator в iterator». Это криво и долго.
А>>9. list А>>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). АТ>А что делать? Так устроен мир. Именно к STL это мало относится.
Неудачный дизайн. Я бы добавил проблемному splice-у дополнительный параметр:
template<...>
class list
{
...
int m_Size;
...
int size() const
{
return m_Size;
}
...
void splice(iterator Pos, list& Source, iterator Begin, iterator End, int Len)
{
// Len - длина перетаскиваемой последовательности
assert(Len == distance(Begin, End));
if (m_Allocator == Source.m_Allocator)
{
// перетащить дёшево (shallow) за константное время
...
m_Size += Len;
Source.m_Size -= Len;
}
else
{
// перетащить дорого (deep) за время O(Len)
...
}
}
...
};
.
А>>10. string А>>10.1. Если программа много работает с текстом, то string (или его аналог) — ходовой тип. При этом желательно, чтобы неявное копирование string-а было дешёвым. Для этого реализация string-а может использовать разделяемый (между несколькими string-ами) буфер с подсчётом ссылок. Но string спроектирован в mutable стиле, поэтому у него есть не-const методы begin, end, rbegin, rend, operator[] и at. Если реализация string-а считает ссылки, то эти методы делают copy-on-write (даже если вы не собираетесь ничего менять) и запрещают разделяемость буфера. АТ>По-моему это вопрос качества реализации. Нет?
Неудачный дизайн влечёт корявую реализацию. Я бы сделал так:
template<typename TChar, ...>
class basic_string2
{
private:
// структура переменной длиныstruct Data
{
int Refs;
...
int Len;
#if defined(_MULTI_THREAD) && defined(_DEBUG)
// прописка; если равно 0 (по умолчанию), то строку можно использовать в любом thread-е
DWORD HomeThreadId;
#endif
TChar Chars[1]; // (Len + 1) TChar-ов
};
Data* m_pData;
...
void check_thread() const
{
#if defined(_MULTI_THREAD) && defined(_DEBUG)
// проверить прописку
assert((m_pData->HomeThreadId == 0) || (m_pData->HomeThreadId == GetCurrentThreadId()));
#endif
}
...
public:
...
void restrict_to_cur_thread_only()
{
#if defined(_MULTI_THREAD) && defined(_DEBUG)
assert(m_pData->HomeThreadId == 0);
m_pData->HomeThreadId = GetCurrentThreadId();
#endif
}
...
int len() const
{
check_thread();
return m_pData->Len;
}
...
// прямой доступ к буферу на чтениеconst TChar* c_str() const
{
check_thread();
return m_pData->Chars;
}
...
// неявное копирование дёшево
basic_string2(const basic_string2& Source) { ... }
basic_string2& operator=(const basic_string2& Source) { ... }
// пример использования:
// string2 s = "abc";
// string2 t = s; // дешёвое копирование (shallow)
// assert(s.c_str() == t.c_str()); // общий буфер
...
// дорогое копирование явно
basic_string2 DeepCopy() const { ... }
// пример использования:
// string2 s = "abc";
// string2 t = s.DeepCopy(); // дорогое копирование (deep)
// assert(s.c_str() != t.c_str()); // разные буферы
...
TChar operator[](int Index) const
{
check_thread();
assert((0 <= Index) && (Index <= m_pData->Len)); // можно читать завершающий '\0'return m_pData->Chars[Index];
}
...
// mutable-стиль, по желаниюvoid set_at(int Index, TChar c)
{
check_thread();
assert((0 <= Index) && (Index < m_pData->Len)); // нельзя писать в завершающий '\0'
// copy-on-write
...
m_pData->Chars[Index] = c;
}
...
// прямой доступ к буферу на запись
TChar* lock(int Len)
{
check_thread();
assert(Len > 0);
...
}
// аннулирует указатель, выданный lock-омvoid unlock() { ... }
...
};
Почти все методы начинаются с check_thread. Это отладочная проверка: можно ли использовать строку в текущем thread-е. WinAPI-шная функция GetCurrentThreadId быстрая (Windows 2000 SP 3):
77E876A1 mov eax,fs:[00000018]
77E876A7 mov eax,dword ptr [eax+24h]
77E876AA ret
поэтому check_thread должен работать быстро.
А>>10.2. Нет завершающего '\0'. АТ>Нет. Не вижу в этом минуса. А придумать ситуацию, когда это неудобно можно всегда.
Абсурд в том, что обычно реализация std::string-а хранит завершающий ‘\0’ (чтобы иметь быстрый c_str), но официально доступ к нему запрещён. Теоретически, может быть реализация std::string-а с умным substr (исходная строка и подстрока разделяют общий буфер), но я такого не видел.
Здравствуйте, ., Вы писали:
>> Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. .>Просто hash_map нестандарна...
Конечно это это плюс STL. Что же ещё?
Людям, как обычно нужно, не чтобы стандартно, а чтобы работалось и дёшево переносилось
Можно хоть свой собственный hash_map с собой таскать всегда
>> Кроме того, string может иметь дорогой оператор копирования. Именно >> поэтому его нельзя использовать для работы с большим массивом строк. >> Плюс фрагментация памяти. .>Тут же string в качестве ключа используется, копирование при помещении в map всё равно будет. Какая разница?
Ну так в std::map<std::string> обычно есть где-то в недрах аналог std::vector<std::string>. а std::vector любит время от времени копировать свои потроха, при этом std::string обычно копируется задорого, да ещё и кучу фрагментирует как подорванное .>Со строками до нескольких килобайт думаю большой разницы не будет. memcmp работает очень быстро.
Ну попробуй, например, родить hash_map и map для словника английского языка например.
Узнаешь много интересного
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском