spamsink: (Default)
[personal profile] spamsink


В данном случае, об егонный комитет по стандартизации, бессмысленный и беспощадный.

Если формировать объект типа std::string посимвольно, то память будет выделяться и копироваться кусками размером 1, 2, 4, 8 и т.п. символов, что хоть асимптотически и линейно, корысти в этом мало.

Впрочем, партия об этом подумала уже давно, и в классе-шаблоне std::basic_string отродясь есть метод reserve(size_type size) - причем это единственный способ управить размером памяти для каждого объекта каждый раз явно; до введения в шаблон дополнительного параметра min_alloc со значением по умолчанию, равным 1 (и с полезным на нашей практике значением порядка сотни-двух), эти архимеды, начиная то ли со Степанова, то ли со Страуструпа, не дотумкали.

Но ладно уж это! Убило меня то, что этот несчастный метод возвращает void даже в С++11!
Т.е. еще лет 10, чтобы было эффективно, нам придется писать не как людям,
return std::string().reserve(много).assign(нечто).append(кое-что);
а как на фортране полвека назад, с переменнымя. Или изобретать собственные классы-велосипеды.

Ну тупы-ы-ы-ые! И этим людям мы доверяем придумывать языки для heavy industrial usage?

Date: 2012-08-28 11:49 pm (UTC)
From: [identity profile] fatoff.livejournal.com
You are so full of wisdom. I personally easily ignore all these imperfections by enjoying other definitely beautiful things in C++ 11 such as move semantics.

Date: 2012-08-29 02:59 am (UTC)
From: [identity profile] ormuz.livejournal.com
Насколько я помню, в gcc stl строки были вовсе не такие простые, с copy-on-write семантикой и с нетривиальными оптимизациями
в том смысле, что reserve не может вернуть ничего путного, потому как ничего путного и не делает.

Date: 2012-08-29 03:20 am (UTC)
From: [identity profile] ormuz.livejournal.com
Посмотрел - зря вы
оно хитрое (_S_create), всегда страничку (4096) заранее аллоцирует - то есть то что вы хотите, вы на самом деле не хотите.

Date: 2012-08-29 04:59 am (UTC)
ak_47: (default)
From: [personal profile] ak_47
Обычно в имплементации std::string используется small string optimization, так что большинство юзеров благодарны уже и так. Далее, изменение готового стринга операция значительно более редкая, чем единоразовое создание стринга, который не меняется за свою жизнь. У вас задача несколько отличается от мейнстримной: во-первых, стринги подлинее будут; во-вторых, часто меняются. Вот для таких и сделали возможность подставить свой аллокатор и вытворять с памятью что угодно. Остальным 99% это всё не надо. И даже если раз в жизни надо, то перформанс ни разу не критичен.

Код вида return std::string().reserve(много).assign(нечто).append(кое-что); пишут далеко не все люди. Я считаю это весьма
некрасивым проявлением джаваизма, который, к сожалению, пролез в другие языки. Произошло это, в основном, благодаря двум факторам: а) понижение квалификации занятых в отрасли и б) появление auto completion в редакторах. Поэтому такую колбасу клепать стало легко и быстро. А в Индии время на код тратить не любят.

Я как раз имею тенденцию заводить переменные (как в Фортране, ага), потому что не только читабельность повышается, но и в дебаггере их легко видеть. А не надо выковыривать из регистров временные инстансы.

Date: 2012-08-29 12:29 pm (UTC)
ak_47: (Default)
From: [personal profile] ak_47
Насколько я знаю, что у мелкомягких, что у ГНУтых, small string optimization это 16 символов. Я не помню уже точно, становятся ли они 16 символами для std::wstring или ужимаются до 8.

Насчёт хорошего кода я никогда не против. Но мне лично конструкции вида a().b().c()...z() читаются плохо. Я люблю разбивать. У С++ есть много косяков и std::basicstring не самый удачный класс в библиотеке. С этим согласен. Но не ужас ужас.

Date: 2012-08-29 12:52 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
а если слинковать с tcmalloc'ом или jemalloc'ом?

Date: 2012-08-29 04:14 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
это понятно, просто любопытно насколько эти аллокаторы сгладят проблему
все равно, каждый раз делать такие микрооптимизации неэффективно
если уж заморачиваться, то со статическими буферами в thread local storage (все равно строка будет скопирована по возвращению)

Date: 2012-08-29 06:19 pm (UTC)
From: [identity profile] lider.livejournal.com
" для heavy industrial usage"

И пусть никоґда ґлаз не устанет смотреть на чужую тяжелую работу!!!

Date: 2012-08-29 06:54 pm (UTC)
From: [identity profile] ormuz.livejournal.com
действительно, странно.
Впрочем,
std::string dotted_pair2(char *a,char *b) {
  static char *t = new char[256];
  string s(t,256);
  return s.assign(a).append(1,'.').append(b);
};

не тормозит.

Date: 2012-08-29 09:48 pm (UTC)
ak_47: (Default)
From: [personal profile] ak_47
У меня сейчас под рукой нет ГНУ посмотреть что там со стрингом. Но в Студии (т.е. от Dinkumware) стринг начиная как минимум с 2008 и по сей день имплементирует small string optimization. И размер стринга, соответственно, больше 8. Я сейчас проверил: релиз - 24, дебаг - 28 (для 32-бит кода). Для 64-бит билда: релиз - 32, дебаг - 40.

Трюк там в том что в стринге юнион, который хранит либо поинтер на буфер, либо массив на стеке до 16 элементов (включая '\0'). Я не знаю почему выбрали именно 16. Наверное достаточное количество стрингов попадает в этот интервал и оверхед не слишком значительный.

Насчёт того откуда известно что стринги редко меняются. Это anecdotal evidence из личного опыта. Какой-либо статистики на руках нет. Хотелось бы, конечно, увидеть менее голословные свидетельства. :)

Date: 2012-08-29 10:27 pm (UTC)
ak_47: (Default)
From: [personal profile] ak_47
Если не секрет, то почему такие мучения от стринга больше чем sizeof(void*)?

Date: 2012-08-29 10:38 pm (UTC)
ak_47: (Default)
From: [personal profile] ak_47
Да, сурово у вас там. Обычно же всякие NRVO/RVO начинают применяться компилятором. Хотя, конечно, тоже будет оверхед.

Насчёт sizeof(string) == sizeof(void*), я доберусь до кода, посмотрю что там они сделали. Есть предположение что там хитрый финт ушами и на самом деле данных больше. Но это всё хозяйство упрятали именно для того, чтобы стринг в регистр помещался.

Date: 2012-08-30 03:23 am (UTC)
From: [identity profile] fatoff.livejournal.com
> Я считаю это весьма некрасивым проявлением джаваизма

На Java писал довольно мало, но, IMHO, в данном конкретном случае проявлением джавизма было бы использование StringBuilder. А это для конкатенаций и массовых перемещений символов как раз таки правильный подход, который STL неплохо бы перенять.

Но не могу сказать, чтобы меня это слишком сильно волновало, тем не менее... для редких но метких оптимизаций сделать string_builder дело не то чтобы очень сложное, но опять же, надо делать...
Edited Date: 2012-08-30 03:24 am (UTC)

Date: 2012-08-30 06:24 am (UTC)
From: [identity profile] http://users.livejournal.com/_navi_/
Если ты такой у-у-умный, то почему памятник Пушкину ты до сих пор не в комитете? (Я на самом деле только наполовину шучу, я очень согласен с твоими взглядами на C++ :-) )

Date: 2012-08-30 07:18 am (UTC)
From: [identity profile] http://users.livejournal.com/_navi_/
Я с год назад задавался вопросом, как в такие комитеты люди попадают (в контексте разговора про комитет по C++). Как мне объяснили люди не знакомые с вопросом напрямую (но вроде знакомые косвенно), было бы желание. Меня правда интересовало немного другое: откуда берётся в таких комитетах «юная кровь», и как поддерживается средний возраст: порог вхождения туда, по-моему, очень высок.

Date: 2012-09-09 06:46 am (UTC)
From: [identity profile] e2pii1.livejournal.com
<<
до введения в шаблон дополнительного параметра min_alloc со значением по умолчанию, равным 1 (и с полезным на нашей практике значением порядка сотни-двух), эти архимеды, начиная то ли со Степанова, то ли со Страуструпа, не дотумкали
>>

Это они сознательно не сделали: цель стандартной библиотеки - минимально-достаточная базовая функциональность, а не "все что угодно что может кому-то понадобиться". Это Страуструп в своей книге объясняет (и это смысленно чтоб библиотека имела обозримый размер). Делайте свой класс полезный в вашей практике.

А с reserve() возвращающим ссылку на объект Вы совершенно правы, это бы им стоило сделать.

Date: 2012-09-09 08:30 am (UTC)
From: [identity profile] e2pii1.livejournal.com
Но ведь многим не нужен этот "параметр min_alloc". И им изучая документацию придется затратить своё время на лишнюю для них статью. Не факт что ваша выгода от этой доп.функциональности перевесит эти совокупные потери времени.

Date: 2012-09-10 05:44 am (UTC)
From: [identity profile] e2pii1.livejournal.com
аллокатор необходимая базовая функциональность, тем кому он нужен без него не обойтись легким написанием своего класса-надстройки

Date: 2012-09-10 07:26 am (UTC)
From: [identity profile] e2pii1.livejournal.com
Почему ?
Сделать свой класс derived from STL container и определить у него используемые вами конструкторы containerа с телом { reserve(min_alloc); }

Date: 2012-09-10 07:42 am (UTC)
From: [identity profile] e2pii1.livejournal.com
тогда наверно свой аллокатор придется делать (derived из STL аллокатора)

Date: 2012-09-10 08:20 am (UTC)
From: [identity profile] e2pii1.livejournal.com
Да, вызовов mem_alloc()/new для 1,2,4,8... вероятно можно избежать захватив в своем allocator::allocate() минимум N и потом возвращая тот же буфер если просят allocate меньше N. Но перекопирований строки STL контейнером при росте через 2^k тaк не избежать.

Date: 2012-09-10 08:45 am (UTC)
From: [identity profile] e2pii1.livejournal.com
захватить 2^n+2^(n+1) и возвращать тo buf, тo buf+2^n

Date: 2012-09-10 09:13 am (UTC)
From: [identity profile] e2pii1.livejournal.com
allocator::allocate(1) захватывает буфер длины 127 и запоминает его в allocator-объекте.
allocator::allocate(2^k, 0<k<7) возвращает буфер+(2^k)-1

Date: 2012-09-10 09:23 am (UTC)
From: [identity profile] e2pii1.livejournal.com
Можно просто сделать аллокатор оптимизированный под захват кусков размера 1,2,4,8... - захватывать сразу большие буфера для каждого из размеров и держать там список свободных блоков. Тогда каждый allocate() будет проходить за малую константу времени.
Если стандартный аллокатор уже так не реализован.

Profile

spamsink: (Default)
spamsink

February 2026

S M T W T F S
12345 67
8 91011 121314
15161718 192021
22 2324 25262728

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 6th, 2026 05:39 am
Powered by Dreamwidth Studios