| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > sizeof(std::string) == 32, Почему ??? |
| Автор: andrew_121 29.7.2008, 10:53 | ||
Кто нибудь, объясните, почему:
Это что за нехороший класс такой. Его размер больше хранимой в нем строки! |
| Автор: SABROG 29.7.2008, 11:13 |
| Во втором случае у тебя массив из 4х экземпляров класса std::string. А вообще здесь тоже народ возмущается: http://forums.msdn.microsoft.com/en-US/vclanguage/thread/9a59970d-c7bf-4ed5-8267-e482c4e461a7/ |
| Автор: Mayk 29.7.2008, 11:22 |
| Ужжас. Целых 32 байта. Как жить дальше? Неужели в системных требованиях придется писать "1 mb. ram"? |
| Автор: SABROG 29.7.2008, 11:23 | ||||
Не, не. sizeof() возвращает размер в байтах. Посмотрите файлик basic_string.h, там действительно напихали всего. |
| Автор: Lazin 29.7.2008, 11:35 |
| упс, я думал он в биты перевел... |
| Автор: andrew_121 29.7.2008, 12:08 |
| SABROG - Я всегда юзал сей класс даже не задумываясь об этом. В данном случае мне нужно создать массив из 6 000 000 объектов, и памяти явно не хватает, ~1.3 Gb сжирает, поэтому я и решил проверить. Проверил, расстроился... Лучше бы и не зал сего |
| Автор: SABROG 29.7.2008, 12:15 | ||
Ну пустые классы занимать будут тогда 183 мегабайта в твоем массиве. Я не знаю какая у тебя задача, но можно попробывать использовать массив обычных char'ов, а строки разделять \0'ми. Но это конечно, если есть возможность последовательного заполнения массива и еще надо будет написать алгоритм поиска строки по индексу. |
| Автор: Lazin 29.7.2008, 12:16 |
не многовато-ли будет для оперативной памяти? такой массив данных нужно хранить на в файле или в БД... |
| Автор: andrew_121 29.7.2008, 12:19 | ||
Неа, так не пойдет... Нужно изменять значение строк. Добавлено через 2 минуты и 58 секунд Массив-то и хранится в нескольких файлах. Но для операций над ним, нужно загрузить в память. |
| Автор: SABROG 29.7.2008, 12:24 |
| Любопытный бенчмарк на сравнение Си и STL строк, не в пользу последних: http://deepencpp.blogspot.com/2007/08/stdstring-vs-const-char-comparison.html Lazin, а у меня тоже подобная ситуация возникала, из базы данных делается выборка окола 1.5 млна записей, по 20 колонок в каждой. Т.е. 30 млн. строк., которые распихваются по структурам и векторам. Сжирается вся оператива и вся виртуалка. Далее происходят операции типа парсинга этого всего дела. Объединения, конвертация из текста в числа и т.п. После того как алгоритм отработает результат пихается в Excel файл и после этого память освобождается. Теоретически можно как-то выгружать ненужные участки и подгружать новые по 10 раз, но это скажется на скорости работы программы. Т.е. либо скорость, либо память. Добавлено через 4 минуты и 4 секунды Тогда массив указателей на динамеческие строки типа char. Передал в какую-нибудь строковую функцию, она вернет новый указатель с изминенным текстом, старый удалиш и замениш новым. Правда все будет распихано по памяти неизвестно как. |
| Автор: W4FhLF 29.7.2008, 12:30 |
| Давно уже пора переходить на x64 и не мучиться с ограничением 2гб. |
| Автор: vinter 29.7.2008, 12:33 | ||||||
если это не расчитано на машины с большим кол-вом оперативы, аля серверы. Тогда надо подумать, не ошиблись ли вы случаем с выбором алгоритма?
ничего любопытного, STL реализаций много, а значит этот бенчмарк идет лесом, и второе: по вашему за удобство ничем не надо расплачиваться?
+1 |
| Автор: Lazin 29.7.2008, 12:34 |
неужели для обработки одной строки нужно знать все остальные, может как-нибудь, в несколько проходов можно все обработать? |
| Автор: SABROG 29.7.2008, 12:38 | ||
Хотябы light-weight классы строковые сделали бы, где можно реализовать хотябы простые операции без которых невозможна работа и с обычными char массивами. |
| Автор: andrew_121 29.7.2008, 12:39 | ||||
Гм... Согласен! Не хотелось бы в С спускаться...но, похоже придется.
Непонял... |
| Автор: SABROG 29.7.2008, 12:44 | ||||||
Там если комменты почитать, то есть и обратные результаты. Пока сам не потестиш с разными реализациями не примешь правильное решение. Надо что-то с алгоритмом думать. Если программа начинает работать со свопом, то смысла тогда уже нет все держать в памяти, т.к. это равнозначно обычному чтению байтов из файла. |
| Автор: vinter 29.7.2008, 12:44 |
ОС тоже кушать хочет |
| Автор: andrew_121 29.7.2008, 12:45 | ||
К примеру...?
Думаю - ДА. Это алгоритм унификации слов. Т.е. есть каталог котором хранятся файлы словарей(простые .txt). Так вот при добавления нового файла, нужно проанализировать все словари на предмет повторения слов. Сами понимаете, итераций...ого-го |
| Автор: W4FhLF 29.7.2008, 12:47 |
Ты чего не понял Всегда есть два направления: память и быстродействие. В любом случае работа с данными находящимися в физической памяти(файл подкачки к которой не относится) будет всегда быстрее. Нужно найти золотую середину. Действительно ли у тебя присутствует наобходимость хранить все 6млн. объектов в памяти? |
| Автор: Lazin 29.7.2008, 12:49 | ||
для процесса - 2Гб кстати можно использовать паттерн light weight хранить не массив строк, а массив объектов каждый объект хранит номер строки (или смещение) в файле если объект не используется, то он хранит необходимый минимум данных, для того что-бы он мог считать себя из файла если к объекту происходит обращение, то он считывает свои данные из памяти(так как знает откуда читать) прозрачно для клиента Вообще это дурной подход к делу, так как нужно заботиться о масштабировании, завтра тебе понадобится обработать не 6 000 000 объектов, на несколько порядков больше, и ни в какую память они не влезут, что будешь делать? Добавлено через 1 минуту и 38 секунд
ну так это просто индексация, все читать не обязательно... |
| Автор: andrew_121 29.7.2008, 12:52 | ||
Согласен. Нет, памяти хватает. Но как-то медлено это все происходит... Я просто кимарю на раб. месте, пока день не закончится. В данный момент в словарях 5 746 337 слов, операция над ними занимает ~13 часов на P4 Core 2 Duo 3.2Ghz? 2Gb ram DDR2-Dual. Может есть какие-то иные методы...? |
| Автор: vinter 29.7.2008, 12:53 |
винду можно с ключиком запустить и будет 3 |
| Автор: W4FhLF 29.7.2008, 12:55 |
Да БД однозначно. Добавлено через 1 минуту и 38 секунд Надо сделать ещё одну оговорку. БД может не подойти в случае, если исходный формат, в котором будут поступать данные, всегда будет txt и от тебя это не зависит. И в случае, если данные словари достаточно часто меняются. |
| Автор: Lazin 29.7.2008, 12:57 | ||
а на что время в основном тратится? |
| Автор: andrew_121 29.7.2008, 12:59 | ||
Абсолютно согласен. Исправлю. |
| Автор: W4FhLF 29.7.2008, 13:00 |
| В случае, если структура файла меняется редко или она просто дополняется новыми словами с конца, можно хранить не слова, а хеши. Ессно проиндексировать, но здесь простое соответветствие -- хеш+позиция_в_файле |
| Автор: Lazin 29.7.2008, 13:00 |
я просто подумал, если происходят частые, случайные обращения к разным записям словаря (если одна запись словаря - одна запись БД), и частые их апдэйты, то не факт что будет быстро, хотя я не работал с БД... |
| Автор: SABROG 29.7.2008, 13:00 | ||||
Может есть смысл воспользоваться одной из баз данных ? В них уже реализованы алгоритмы поиска, сравнения, индексации, экономии памяти и т.д. А вообще словари надо попросту специальным образом проиндексировать. Например создаешь файл индекса, где букве "А" соответствует стартовое смещение в файле каждого словаря и длинна участка. В итоге в память ты уже будешь загружать не все слова, а только на букву "А", далее сравниваешь сначала строки по размеру. Если длинна строк не идентична, то они уже не равны (правда не знаю, может функция сравнения строк уже так и делает. |
| Автор: W4FhLF 29.7.2008, 13:04 | ||||
Тогда ещё отсортировать надо Добавлено через 6 минут и 29 секунд
Всё-таки лучше действительно посчитать один раз хеши. Возьми какую-нибудь быструю хеш-функцию, например adler32, создай массив простых структур/классов, которые бы хранили хеш слова + позицию слова в файле, можно ещё длину слова. Если основная операция сравнение слов, то здесь ты многократно выигрываешь. Мало памяти, высокая производительность как раз в случае проверки дубликатов. |
| Автор: Любитель 29.7.2008, 13:11 |
| Предварительно обработать данные - без сомнения. Создать какое-нибудь индексное B-дерево. А затем легко и приятно всё, что надо добавлять и пр. txt и прямой перебор - явно не удачное решение |
| Автор: andrew_121 29.7.2008, 13:22 |
На std::sort(), std::unique() и далее на итерации по словам между словарями. |
| Автор: Lazin 29.7.2008, 13:35 |
тогда логично для этого использовать структуры данных, на которых эти операции имели бы сложность О(1) или O(ln(N)) |
| Автор: andrew_121 29.7.2008, 15:00 |
| Всем Преогромное Спасибо Приступаю к реализации. |
| Автор: SABROG 29.7.2008, 18:33 | ||||||||||||||
Решил тоже сравнить на своей тачке скорость: gcc
msvc
А это сравнение идентичных строк удвоенной длинны (gcc):
Собирал проги без каких-либо ключей оптимизации, т.е. тупо:
Тесты проводились под Win2000SP4. |
| Автор: Lazin 29.7.2008, 18:55 |
| SABROG, в VS по умолчанию stl проверяет выход за границы контейнера, это отключается каким-то макросом... результат для msvc должен быть близок к результату gcc кстати на очень длинных строках результат может каардинално измениться... |
| Автор: SABROG 29.7.2008, 18:58 | ||
Запущу тесты на ночь на длинных строках. Завтра запощу. |
| Автор: Lazin 29.7.2008, 20:18 |
| ну не на столько-же длинных |
| Автор: Torsten 30.7.2008, 08:36 | ||
Это сделано специально, чтобы когда ты увеличиваешь размер строки память не пришлось перевыделять (новую выделить, скопировать элементы, старую удалить). Так делают все stl контейнеры. Так же есть метод reserve, через который можно установить желаемый размер, но он будет установлен, только если текующий зарезирвированный размер меньше. |
| Автор: vinter 30.7.2008, 09:38 | ||
string хранит указатель на память, размер строки не влияет на размер string зависит от реализации. |
| Автор: SABROG 30.7.2008, 10:31 | ||
Сегодня не судьба. Ночью в офисе вырубило электричество все результаты пропали. |
| Автор: Любитель 30.7.2008, 13:25 | ||
Размер самой строки через sizeof вообще не возможно получить |
| Автор: andrew_121 30.7.2008, 13:59 | ||||||||
Это понятно. Но откуда взялись 32 байта Это походу 8 указателей, или что-то еще...бред... А в Лине кто-то проверял? Щас в Mingw проверю. Добавлено через 13 минут и 42 секунды Проверил. Вот результаты.
Для MSVC-2008, компилил из командной строки, без каких либо опций.
И для Mingw:
Тоже без опций. Разница на лицо. |
| Автор: Любитель 30.7.2008, 14:23 |
| О, ещё аллокатор и итератор для начала. Может и для конца. А итератор - это уже не 4 байта... |
| Автор: Lazin 30.7.2008, 14:25 | ||
в студии нужно компилить с таким дефайном
что-бы все было честно |
| Автор: SABROG 30.7.2008, 14:58 | ||||||
А студия 2005 все-равно выдает 28 байт против 4х в mingw (gcc).
|
| Автор: Lazin 30.7.2008, 15:19 | ||
ну еще-бы, он вроде-бы должен проверку итераторов отключать да, и
|
| Автор: Любитель 30.7.2008, 15:23 | ||||
Блин, и в чём мораль? Смотрим заголовычные файлы МинГВ. Все данные строки хранятся через некий _M_dataplus, в котором есть:
И куча реинтерпрет-кастов затем. Чтобы получить, например, _Rep:
Зачем всё так сложно? Скорей всего виноват референс-каунтинг. Если хочется сравнить реально память, занимаемую строками - создаём огромное количество этих строк и смотрим, сколько памяти жрёт процесс. |
| Автор: SABROG 30.7.2008, 15:24 | ||||||
А я и так и так пробывал, разницы нету Последовал совету Любителя, вот код:
Создается 6 млнов экземпляров пустых классов: ![]() В итоге: mingw (gcc) - 141 896 kb msvc - 235 716 kb |
| Автор: andrew_121 30.7.2008, 15:50 |
| SABROG - Мда... Я уже поднимал тему по замене std::string из-за малого функционала. Похоже теперь появился еще один повод искать замену std::string С каждым днем все больше радости |
| Автор: W4FhLF 30.7.2008, 15:55 |
А если хотя бы 1 символ в строку записать? Может в случае mingw для пустых строк просто не хранится никакой служебной инфы. |
| Автор: Любитель 30.7.2008, 15:58 |
| И ещё - везде надо включать оптимизацию. Иначе сравнение не объективно. |
| Автор: SABROG 30.7.2008, 16:19 | ||||
Ну для gcc -O3 я могу прописать, на другие ключи у меня знаний не хватит. А для cl я вообще не знаю ключей оптимизации. С таким кодом я вообще получил неожиданные результаты:
gcc - 376 604kb msvc - 235 716kb Попробывал провести тест снова с пустыми классами и опять msvc продул, а с заполненными продувает gcc. Скомпилил прогу с помощью gcc с максимальной оптимизацией -O3, результат никак не изменился. |
| Автор: Lazin 30.7.2008, 16:20 | ||||
| немного потестировал пример из блога deepencpp для разных строк для коротких строк l1 и l2 - длины строк, конкретные значения не важны, важно отношение - больше, меньше...
для длинных
честно говоря я думал что на длинных строках результаты будут равны, но все оказалось еще интереснее... Добавлено через 44 секунды зы компилятор vs2005, ключи /O2, /Ot |
| Автор: W4FhLF 30.7.2008, 16:22 |
/O1 - size /O2 - speed /Ox - full то то |
| Автор: Любитель 30.7.2008, 16:24 | ||
1. cl /? 2. Скажем, cl /Ox.
Можно увидеть вариант со включенной отимизацией? |
| Автор: SABROG 30.7.2008, 16:32 |
Добавил ключи /Ox и -O3 соотв, результаты не изменились никак вообще. Оптимизация вообще никак не повлияла на тесты с пустыми и заполненными классами. Т.е. осталось все прежним. Если сравнивать два теста с пустыми классами и заполненными, то можно увидеть, что размер занимаемой памяти для msvc не меняется вообще. Видимо msvc проигрывает в первом тесте из-за того, что резервирует память изначально, чего не делает gcc. |
| Автор: andrew_121 30.7.2008, 16:39 |
| Гм... Я в ступоре |
| Автор: SABROG 30.7.2008, 16:54 | ||
Вот кстати еще один вариант:
Результат: msvc - 235 716kb gcc - 282 932kb А тут я решил увеличить количество строк до 90 млн.ов c непустыми классами, результат мне не очень понравился: gcc - 563 712kb msvc - 352 452 kb |
| Автор: Lycifer 30.7.2008, 16:58 |
| Boost::array STL == как на ресурсы, работать быстро - гдк то слышал, хотя работать быстро не получается(во первых память не вовремя олсвобождается, а во вторых new,delete,malloc,realloc - медленнеы так как ищют дырки в памяти, то и есть свободные места) |
| Автор: Любитель 30.7.2008, 17:00 | ||
Ой, а можно по-русски? Добавлено через 21 секунду Да, и кстати boost::array - это для массивов постоянного размера. |
| Автор: SABROG 30.7.2008, 17:11 |
| А вот в подтверждение моих слов результаты метода max_size(), который возвращает максимальное количество символов, которое может содержать экземпляр класса std::string: gcc - 1073741820 msvc - 4294967294 Т.е. все-таки msvc хоть и имеет размер класса 28 байт, но он резервирует много памяти для новой строки о чем говорит функция capacity(), которая возвращает 15 байт для msvc и 0 байт для gcc. |
| Автор: just_geek 30.7.2008, 18:25 |
| Еще ради интереса stlport бы сравнили на обоих компиляторах |
| Автор: vinter 30.7.2008, 18:46 |
| мне вот интересно к чему эти тесты? если бы С строки оказались быстркее, вы бы отказались от string? иЛи из-за того, что msvc дает меньший размер все бросят gcc? по моему это пустая трата времени... |
| Автор: Любитель 30.7.2008, 18:48 |
| А к чему любые подобные тесты? |
| Автор: SABROG 30.7.2008, 19:25 | ||
Ага, а потом начнется, а вот еще и для watcom сравните и для icc и для bcc. А потом на разных платформах, операционных системах. А потом версии библиотек, стабильные/не стабильные. А потом еще и с разными ключами собранные библиотеки. А потом скажут, что сравниваете не верно, код должен быть другой. |
| Автор: andrew_121 30.7.2008, 19:30 | ||
А у меня stlport не собирается для Студии. Вот что сообщает:
Какие мысли? |
| Автор: Torsten 30.7.2008, 20:24 |
| Вы на stlport тестируйте, там честнее будет для всех компиляторов, т.к. у студии собственная stl. |
| Автор: andrew_121 30.7.2008, 22:18 | ||
Вот я и попытался... |
| Автор: SABROG 30.7.2008, 23:36 | ||||||||||||||||
Народ, а че за фигня. Прописал пути:
Пытаюсь скомпилить так:
Получаю:
Меняю на
Получаю
Меняю на:
Опять не компилится. Меняю на полный путь:
Компилиться. Почему линкер не видит ни переменную окружения LIB, ни косвенный путь через -L./LIB/ (даже -L../LIB пробывал с вариациями) ? --- Ага, это спасает отца русской демократии:
|
| Автор: SABROG 31.7.2008, 01:25 |
| Вроде бы собрал STLPort для обоих компиляторов, а размеры классов почему-то не изменились также как и количество занимаемой памяти. Даже как в мануале прописал инклюд первым, видимо компилеры все-таки родной STL включают. Пол третьего ночи, сил уже нету... |
| Автор: Mayk 31.7.2008, 05:24 |
Попробуй в STLPort'овском string'е прописать #error hello world. если сообщение ошибке не вылетит - значит stl port не подключен. если вылетит - подключен |
| Автор: SABROG 31.7.2008, 08:21 | ||||
Прописал этот error в файле "string.h" STLPort'a, снес переменную окружения INCLUDE, прописал в переменной окружения PATH путь с инклюдами STLPort'a в самом начале. Не помогает, все-равно mingw берет старый и все нормально компилит. --- Похоже при компиляции каждый раз нужно задавать непосредственные пути. Так error выдает, что говорит о том, что все-таки STLPort увиделся:
--- Фух, собрал таки наконец. Итак 6 млн.ов классов std::string (STLPort) занимают в памяти: msvc - 189 132kb (Родной STL - 235 716kb) mingw - 188 912 kb (Родной STL - 141 896kb) Пустой класс имеет размер 24 байта для обоих компиляторов. 6 млн.ов строк "hello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, worldhello, world" отнимают приблизительно 1 гиг и 200 мегов памяти и при этом разница между компиляторами не была больше 400кб. |
| Автор: andrew_121 31.7.2008, 12:17 | ||||
| SABROG - Вот ты упертый Я вот поразмыслил. В моем представлении строковый класс должен содержать что-то вроде:
или
И это 12 байт. А на* еще 12 байт, и для чего их использовать...хз... |
| Автор: SABROG 31.7.2008, 13:18 |
Дык я же писал, что у msvc 15 байт в резерве на строку. Т.е. по сути пустой экземпляр класса std::string это готовая строка размером в 15 байт, поэтому нет никакой разницы между пустым классом и заполненным, если строка меньше 15 символов. Делалось это, по видимому, для ускорения работы программы, чтобы не приходилось дополнительно выделять память под каждую строку в зависимости от длинны строки. |
| Автор: Любитель 31.7.2008, 13:35 |
| SABROG, строка хранится в памяти непрерывно. Это вообщем-то факт (чтобы нормально рабоали c_str и data). Поэтому в классе должен быть только указатель на строку. Никак не сама строка. |
| Автор: SABROG 31.7.2008, 13:43 | ||
Я писал раньше, что метод capacity() возвращет количество символов, которое может содержать строка изначально. Эксперимент показал, что размеры занимаемой памяти никак не менялся, если я создавал 6 млн.ов пустых строк, или 6 млн.ов строк длинной меньше 15 символов (hello, world). |
| Автор: Mayk 31.7.2008, 13:45 | ||
Скажи это разработчикам STLport и STL в MS. А то они совсем идиоты. Ещё расскажи им что хранить в классе длину строки не надо. Ибо "только указатель" это наше всё. |
| Автор: Любитель 31.7.2008, 13:46 |
| И? То, что во многих реализациях стл память резервируется заранее - это очевидно. Только к sizeof-у сабжевому это не имеет никакого отношения |
| Автор: Mayk 31.7.2008, 13:46 | ||
| плин не получилось впереёд SABROG'а ответить тьфу блин не склеилось
И где же она резервируется как не внутри класса? Берется из эфира? |
| Автор: vinter 31.7.2008, 13:50 | ||
в классе хранится указатель на выделенную в куче память. Причем тут объект класса?
и что? это размер выделенной памяти, каким образом это должно показать, что память выделена внутри объекта? |
| Автор: Любитель 31.7.2008, 13:53 | ||
Mayk!
Добавлено через 1 минуту и 42 секунды Резервируется, короче, она никак не внутри класса. Ибо размер класса статичен, строки - нет. А очень желательно хранить строку непрерывно (иначе - проблем больше будет). Что касается размера буфера, размера строки, аллокаторов, итераторов и пр. - да, это хранится в самом классе. Не только указатель, но никак ни сама строка. Добавлено через 2 минуты и 36 секунд К слову - Dinkumware STL. Платно доступна, кстати, для гцц |
| Автор: Lazin 31.7.2008, 14:04 |
| ну и понаписали вы тут, мне кажется автору топика вовсе не обязательно хранить строки, достаточно хранить в памяти хэш, 32 бита и никакой тебе динамической памяти, указателей и прочего |
| Автор: SABROG 31.7.2008, 14:46 |
Какие алгоритмы могут дать хэш размером в 32 бита ? Я правильно понимаю "хэш" в данном контексте это уникальное значение, которое берется путем математических манипуляций с уникальной строкой. Т.е. если была строка "Hello, World" и я поменяю W на прописную w, то хэш уже будет другой. И хэш будет мне гарантировать, что в базе не появится строка с подобных хешем. Когда я подобное искал, то не нашел алгоритмов с хэшами меньше 128 бит и то они не гарантировали уникальности. В итоге пришел к выводу, что экономнее хранить строки как есть, т.к. хэши даже для однобайтовых строк слишком длинные. |
| Автор: Любитель 31.7.2008, 15:02 |
| Хеш - не может быть абсолютно уникальным |
| Автор: W4FhLF 31.7.2008, 15:05 | ||
http://en.wikipedia.org/wiki/Adler-32 Для нескольких миллионов слов пойдёт.
Как они могут гарантировать уникальность? Сколько всего состояний может принять последовательность 128 бит? 2^128. А сколько всего состояний может принять последовательность, например, из 256 бит? Ясно, что 2^256 >> 2^128 и что меньшая последовательность в прицнипе не сможет хранить все состояния первой. Тут вопрос вероятности, а в нормальных хеш-функциях они очень малы, поэтому ими пренебрегают. |
| Автор: Любитель 31.7.2008, 15:10 | ||
Ну, если быть точным - для строки это в некоторой мере возможно, учитывая, что символом с кодом ниже 32 у нас нет. |
| Автор: Lazin 31.7.2008, 15:21 | ||
boost::hash пишет хэш в size_t, 2^32 = 4 294 967 296 количество слов = 6 000 000 так что коллизии маловероятны... |
| Автор: andrew_121 31.7.2008, 15:45 |
Не согласен. Если в цикле нужно проверять размер одной и той же строки, то это расходы на strlen(). Плюс, необходимо знать размер вместимости строки, и предварительно выделять с запасом, чтоб избежать постоянного перевыделения памяти. имхо. |
| Автор: UnrealMan 1.8.2008, 02:18 | ||
Сделано специально для малых строк. Таким образом малые строки могут храниться в стеке, что может повысить быстродействие. Если длина строки больше некоторого порогового значения, то для хранения символов используется динамическая память.
Для обсуждаемых здесь реализаций факт, стандарт же не гарантирует непрерывность. |
| Автор: Mayk 1.8.2008, 05:36 | ||
Если размер строки <константы то его не статичность идёт побоку. Ссылка на Short String Optimisation уже была. |
| Автор: andrew_121 1.8.2008, 12:01 | ||
Глупость |
| Автор: Lazin 1.8.2008, 12:17 | ||
ты учти что менеджер памяти выделяет память под маленькие объекты блоками фиксированного размера, кратными степеням двойки, под строку размером 12 байт может быть выделено 16 байт, а может и 32... плюс обращение к строке в куче дороже чем обращение к строке в стеке, плюс создание и освобождение строки в куче не дешевая операция, в отличии от создания объекта в стеке... блин, так и не понял, нафига тебе хранить кучу строк в памяти? |
| Автор: Vyacheslav 1.8.2008, 17:12 | ||
Стандарт это не регламентирует в отличие от непрерывной памяти для vector. И c_str и data как раз могут не отражать как на самом деле хранится строка. |
| Автор: Любитель 1.8.2008, 17:21 | ||
Согласен. Но, с точки зрения реализации - зачем нам неконстантная сложность для c_str и data? |
| Автор: vinter 1.8.2008, 17:24 | ||
стандарт может и не регламентирует, но врядли вы найдете реализацию string где итераторы не являются обычными указателями. |
| Автор: phprus 2.8.2008, 18:44 | ||||
Задача не очень понятна. Исходные данные: 1) много файлов содержащих слова 2) новый файл со словами Возникают вопросы: Что нужно получить в результате? В случае если нужно получить один результирующий файл в котором будут все уникальные слова, то имеем элементарную задачу. Сливаем все слова в один файл, сортируем его сортировкой слиянием ( О(n*log(n)) ) и за О(н) удаляем дублирующиеся слова. Это наиболее быстрое из всех возможных решений, кроме того оно не требовательно к оперативной памяти. В некоторых случаях для решения этой задачи достаточно стандартной *nix'овой утилиты sort аналоги которой есть и под винду. Если нужно новый файл очистить от тех слов, которые есть в старых файлах, то можно слить все старые файлы в один, отсортировать его, после чего задачу поиска дублей можно решить за один проход по обоим файлам. Если что-то еще, то уточни задачу, но очень похоже, что ты что-то не то делаешь. Не похоже что-бы подобная задача требовала загрузки всех данных в память. Хэш-таблицы тут не подойдут, так как потребуется дополнительное время на из создание, а во вторых в связи с возможностью коллизий при каждом поиске нужно будет сравнивать не только вычислять и сравнивать хэш-коды, но и сравнивать сами строки, что приведет фактически к 2-х кратному росту числа проходов по данным. |
| Автор: W4FhLF 2.8.2008, 18:55 | ||
Ну это в теории конечно так красиво. Попробуй отсортировать файл с 10 млн. слов, это займёт никак не меньше времени, чем просчёт и построение хеш-таблиц. Приведи такую коллизию для двух реально существующих слов в нашем или английском языке хотя бы для функции adler32. |
| Автор: Mayk 2.8.2008, 19:13 | ||||
а вообще можно и не руками писать. а юзать готовое
говорят, что современные базы данных умееют импортировать тектсовые файлы. |
| Автор: phprus 2.8.2008, 21:53 | ||||||
Проверял. Файл из 10 млн. строк длинной от 5 до 25 символов ( 152 Мб ) сотритуется на моем ноутбуке утилитой sort за 2 минуты 13 секунд. Хэш-таблица может быть более ресурсоемкой, так как требует дополнительных сравнений строк, что-бы разрешать возможные коллизии. Кроме того если сами сравниваемые строки хранить на диске, то в результате будет много чтений из различных участков файла, а это гораздо медленнее непрерывного чтения в случае сортированных файлов.
В английском языке потенциально бесконечное количество слов. 2^32 меньше бесконечности, по этому коллизии будут. Кстати я совсем забыл о существовании утилиты comm, которая умеет вот что:
Следовательно задача автора темы в случае файлов может решиться вообще без программирования. |
| Автор: W4FhLF 3.8.2008, 06:51 | ||||||
Ну так сложно оценить. Может этот файл уже был близок к отсортированному состоянию? Однако просчёт 10 миллинов хешей на процессоре 3гц займёт ~1 сек.
Да коллизии здесь не аргумент. Число существующих слов не бесконечно. Вероятность сущестсования коллизии не нулевая, но она слишком мала. В крайнем случае можно взять 64 битную хеш-функцию. Тогда на 32х битных системах сравнение будет выполняться за 2 такта в худшем случае, а на 64 битных за 1. Допустим для подчёта контрольной суммы файлов любых размеров в интернете используется md5. Почему-то ещё никто не наткнулся на коллизию, но её вероятность тоже не нулевая. |
| Автор: phprus 3.8.2008, 09:17 | ||||||||
Маловероятно. Но что-бы нормально оценить нужно взять данные автора и сравнить время работы.
Процессора... А сколько памяти займет такая табличка? Она во первых потребует загрузить все слова в память, а ва вторых еще место под саму хэш-таблицу. Кроме того хэш-таблицу в памяти нужно будет каждый раз перестраивать, а вот один раз отсортированные файлы повторной сортировки не требуют.
Возьмем 64 битную хэшфункцию. Она даст нам 2^64 степени комбинаций. Предположим, что у нас такая мегафункция, что она все слова отобразила в разные значения. НО тут возникает проблема, что мы физически не можем создать хэш-таблицу с 2^64 ячеек. По этому придется этот хэш усекать и вот тут уже вероятность появления коллизий значительно возрастает, по этому приходится применять меры по разрешению коллизий и как следствие либо все данные в память, либо большое количество дорогих дисковых операций.
Для md5 можно подобрать второй файл с таким-же хэш-кодом. Кроме того задача контрольных сумм не требует 100% отсутствия коллизий. |
| Автор: SABROG 3.8.2008, 09:21 |
| Для контрольной суммы пойдет и простой CRC32. Контрольная сумма и хэш разные вещи. Я не думаю что в DirectConnect просто так юзают TTH, а не Adler32. |
| Автор: W4FhLF 3.8.2008, 10:26 | ||
Смотря что в ней хранить помимо самого хеша, если упор на скорость то ещё позицию слова и длину хранить надо. Ну для 10 млн. слов метров 100 отожрёт. Слова в памяти хранить как раз нет никакой необходимости. Можно читать файл порциями по 10-20 мегабайт и строить таблицу. А для сортировки что меньше памяти надо? Там-то как раз весь файл в памяти иметь нужно.
Зачем нам такая таблица? Кол-во записей == кол-ву слов. Можно? Ну попробуй подобрать или хотя бы в сети найти примеры таких файлов Нет, я понимаю теория великая вещь. В ней столько всего возможно, но вот практика штука более ограниченная и в ней приходится делать некоторые допущения и это будет всё прекрасно работать и решать поставленную задачу. В данной теме интерес именно прикладной, т.е. теория меня здесь не особо интересует. Добавлено через 12 минут и 54 секунды Ты прав. Я собственно adler32 предложил просто как пример очень быстрой функции и с учётом экономии памяти. Это даже не хеш-функция как таковая Вот было бы интересно взять какой-нибудь более или менее полный словарь русского/английского и посмотреть будут ли там коллизии. Вопрос где взять такой словарь? |
| Автор: phprus 3.8.2008, 11:33 | ||||||||
Это потребуется для разрешения коллизий. Либо все слова держать в памяти, либо в хэш-таблице придется хранить смещения в файлах данных, но это приведет к огромным дисковым тормозам.
А про алгоритмы внешней сортировки вы не слышали? Расход оперативной памяти можно сделать очень маленьким. Поиск по переполненной хэш-таблице вещь чрезвычайно медленная. Количество ячеек в таблице должно быть как минимум на треть больше чем количество записей в ней и и то при таком количестве пустых ячеек коллизии будут. Кстати а можно поинтересоваться вы вообще хоть какие-либо алгоритмы сортировки знаете? А хэш-таблицы реализовывали? Судя по тому, что вы не знаете основ говорит о том, что все-же нет.
Я то как раз и говорю про практику, а вот вы рисуете какую-то идеальную картину при том на столько идеальную, что ее даже в теории быть не может, а не то что на практике.
Алгоритм хэширования коллизий может и не дать, НО в хэш-таблице коллизии будут. Если конечно размер таблицы будет адекватный, а не такой, что количество ячеек будет равно количеству возможных значений хэш-кодов. |
| Автор: W4FhLF 3.8.2008, 13:11 | ||
phprus, в общем видимо я где-то протормозил, но под хеш-таблицей я не имел ввиду структуру данных "hash table". Всё что я говорил про время и память касалось только лишь расчёта хешей для слов, а не их отображения в какую-либо структуру. И когда ты говорил коллизия я это понимал как hash(s1) == hash(s2). Теперь всё ясно.
Да какие дисковые тормоза? В качестве value харнить позиции слов в файле. Файл читать целиком придётся в любом случае(кусками или ещё как-нибудь). А про запись автор ничего не говорил. Он сказал, что надо проанализировать на предмет наличия дубликатов. А это не дисковые тормоза? |
| Автор: phprus 3.8.2008, 14:50 | ||
Вот здесь и всплывут тормоза. Даже для фрагментированного файла последовательное чтение будет быстрее, чем чтение маленьких кусочков из разных участков файла. (Тут так-же не надо забывать про то, что ОС кеширует данные с диска в оперативке, и этот кэш будет эффективнее при последовательном чтении, чем при постоянных перескоках в разные концы файла). В случае сортировки количество чтений из произвольных участков файла будет минимальным, а в случае работы с отсортированными последовательностями будет вообще только последовательное чтение. |
| Автор: W4FhLF 3.8.2008, 15:11 |
| phprus, я понимаю в чём минусы произвольного чтения с диска. Я не понимаю зачем нам читать из разных концов файла? Мы читаем последовательно, хешируем слова, имеем их позиции и составляем из них уже любую структуру. |
| Автор: phprus 3.8.2008, 16:24 |
Вспомни как происходит поиск в хэш-таблице. Вначале по хэшу ищется нужная запись, а потом для того что-бы гарантировать, что это не коллизия сравниваются сами значения. То значение, которое мы ищем у нас в памяти, а вот то значение которое в хэш-таблице у нас на диске и что-бы его получить нужно считать данные с диска. При поиске следующего слова оно у нас будет в памяти, а вот ссылка из хэш-таблицы снова будет вести на диск и при том в совершенно случайную область файла исходных данных. |
| Автор: W4FhLF 3.8.2008, 16:43 |
| phprus, всё понял, я действительно гоню Добавлено через 6 минут и 44 секунды А что если в качестве значения использовать pair<hash, position>? Hash в любом случае вычисляется один раз, позиция известна при первом проходе. Тогда для разрешения коллизий не придётся читать с диска. |
| Автор: phprus 3.8.2008, 19:09 | ||
Не получится. На входе функции поиска у нас строка, а в хэш-таблице смещение в файле. И эти 2 сущности надо как-то сравнивать. Как следствие надо читать строку из файла. |
| Автор: Mayk 4.8.2008, 07:34 |
| Вопрос,задаваемый (n+1)-ый раз: А кто нибудь может доступным языком объяснить почему БД нельзя использовать? |
| Автор: Lazin 4.8.2008, 09:14 | ||
топикстартер желает написать свою БД, имхо. |
| Автор: andrew_121 4.8.2008, 09:33 |
Уже не надо в памяти хранить. Это так для развития, понимания... |
| Автор: W4FhLF 6.8.2008, 15:46 | ||
| В общем выдался свободный часок и я таки реализовал то, что предлагал. Т.е. считать хеши и позиции слов. Потом сортировка этого вектора и вывод дубликатов. Перестраховался и в качестве хеша вычисляется md5 и берутся его 1 и 4 блоки. Хеш хранится в __int64. Для вычисления хеша подключил свою когда-то написанную на ассемблере оптимизированную либу для вычисления md5. Поэтому процедура string_hash слегка уродлива В конце программы в консоль выводятся слова, которые имеют дубликаты в словаре. Словари для тестов брал отсюда: http://www.insidepro.com/eng/download.shtml На моём процессоре AMD 2.2 гц на построение таблицы и её сортировку для словаря 2.5 млн. слов уходит ~5 секунд. Меня такой результат вполне удовлетворил так, что решил оставить реализацию как есть. Проект для VS 2008 в аттаче.
|