Проклятье процедурного программирования
Aug. 28th, 2012 04:25 pmВ данном случае, об егонный комитет по стандартизации, бессмысленный и беспощадный.
Если формировать объект типа 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?
no subject
Date: 2012-08-28 11:49 pm (UTC)no subject
Date: 2012-08-28 11:56 pm (UTC)Я пока только облизываюсь. To the point, these particular imperfections leave an impression of shoddiness.
no subject
Date: 2012-08-28 11:58 pm (UTC)no subject
Date: 2012-08-29 02:59 am (UTC)в том смысле, что reserve не может вернуть ничего путного, потому как ничего путного и не делает.
no subject
Date: 2012-08-29 03:20 am (UTC)оно хитрое (_S_create), всегда страничку (4096) заранее аллоцирует - то есть то что вы хотите, вы на самом деле не хотите.
no subject
Date: 2012-08-29 03:31 am (UTC)no subject
Date: 2012-08-29 03:34 am (UTC)std::string dotted_pair(const char * a, const char * b) { std::string ret; return ret.assign(a).append(1, '.').append(b); }работает в полтора раза медленнее, чемstd::string dotted_pair1c(const char * a, const char * b) { std::string ret; ret.reserve(256); return ret.assign(a).append(1, '.').append(b); }если длины a и b не более 100, в среднем 50.no subject
Date: 2012-08-29 04:59 am (UTC)std::stringиспользуется small string optimization, так что большинство юзеров благодарны уже и так. Далее, изменение готового стринга операция значительно более редкая, чем единоразовое создание стринга, который не меняется за свою жизнь. У вас задача несколько отличается от мейнстримной: во-первых, стринги подлинее будут; во-вторых, часто меняются. Вот для таких и сделали возможность подставить свой аллокатор и вытворять с памятью что угодно. Остальным 99% это всё не надо. И даже если раз в жизни надо, то перформанс ни разу не критичен.Код вида
return std::string().reserve(много).assign(нечто).append(кое-что);пишут далеко не все люди. Я считаю это весьманекрасивым проявлением джаваизма, который, к сожалению, пролез в другие языки. Произошло это, в основном, благодаря двум факторам: а) понижение квалификации занятых в отрасли и б) появление auto completion в редакторах. Поэтому такую колбасу клепать стало легко и быстро. А в Индии время на код тратить не любят.
Я как раз имею тенденцию заводить переменные (как в Фортране, ага), потому что не только читабельность повышается, но и в дебаггере их легко видеть. А не надо выковыривать из регистров временные инстансы.
no subject
Date: 2012-08-29 07:44 am (UTC)Обычно - это где? И что такое small? 8 - маловато будет.
Далее, изменение готового стринга операция значительно более редкая, чем единоразовое создание стринга, который не меняется за свою жизнь.
Откуда это известно?
подставить свой аллокатор и вытворять с памятью что угодно
Не что угодно. У std::allocator нет метода realloc, поэтому он не в состоянии прозрачно реализовать функциональность min_alloc. Если бы такой метод был, я бы им воспользовался.
И даже если раз в жизни надо, то перформанс ни разу не критичен.
Для разработчиков стандарта индустриального языка общего назначения такие рассуждения неприемлемы.
Я считаю это весьма некрасивым проявлением джаваизма
А я - красивым проявлением аппликативного программирования. Прелесть языков высокого уровня в том, что отлаживать приходится всё меньше и меньше.
А в Индии время на код тратить не любят.
Да, поэтому пишут спагетти-код из сотни строк с массой переменных, циклов, присваиваний и прочей лабуды, и потом много часов отлаживают off-by-one errors, вместо того, чтобы подумать 5-10 минут и написать полдюжины строк с полным пониманием происходящего, делающих ровно то же самое безошибочно by construction.
no subject
Date: 2012-08-29 12:29 pm (UTC)std::wstringили ужимаются до 8.Насчёт хорошего кода я никогда не против. Но мне лично конструкции вида
a().b().c()...z()читаются плохо. Я люблю разбивать. У С++ есть много косяков иstd::basicstringне самый удачный класс в библиотеке. С этим согласен. Но не ужас ужас.no subject
Date: 2012-08-29 12:52 pm (UTC)no subject
Date: 2012-08-29 03:43 pm (UTC)no subject
Date: 2012-08-29 03:50 pm (UTC)Я люблю разбивать.
Это пожалуйста. Мой вопрос - почему (зачем?) необходимость разбивать навязывается возвратом void, хотя этого было бы тривиально избежать.
no subject
Date: 2012-08-29 04:14 pm (UTC)все равно, каждый раз делать такие микрооптимизации неэффективно
если уж заморачиваться, то со статическими буферами в thread local storage (все равно строка будет скопирована по возвращению)
no subject
Date: 2012-08-29 04:25 pm (UTC)В refcounted реализации - вовсе нет.
no subject
Date: 2012-08-29 06:19 pm (UTC)И пусть никоґда ґлаз не устанет смотреть на чужую тяжелую работу!!!
no subject
Date: 2012-08-29 06:22 pm (UTC)no subject
Date: 2012-08-29 06:54 pm (UTC)Впрочем,
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); };не тормозит.
no subject
Date: 2012-08-29 07:01 pm (UTC)no subject
Date: 2012-08-29 09:48 pm (UTC)Трюк там в том что в стринге юнион, который хранит либо поинтер на буфер, либо массив на стеке до 16 элементов (включая '\0'). Я не знаю почему выбрали именно 16. Наверное достаточное количество стрингов попадает в этот интервал и оверхед не слишком значительный.
Насчёт того откуда известно что стринги редко меняются. Это anecdotal evidence из личного опыта. Какой-либо статистики на руках нет. Хотелось бы, конечно, увидеть менее голословные свидетельства. :)
no subject
Date: 2012-08-29 10:19 pm (UTC)Во времена оны в GNU было что-то похожее, и пользоваться стрингом было положительно невозможно. А сейчас, когда sizeof(string) == sizeof(void*), оно летает наравне с доморощенным решением.
В нашем опыте построение массы иерархических имен неизбежно приводит к часто меняющимся стрингам. Они слишком короткие и слишком часто нужно их представление в виде си-строки для того, чтобы rope стал приемлемым решением.
no subject
Date: 2012-08-29 10:27 pm (UTC)no subject
Date: 2012-08-29 10:31 pm (UTC)no subject
Date: 2012-08-29 10:38 pm (UTC)Насчёт sizeof(string) == sizeof(void*), я доберусь до кода, посмотрю что там они сделали. Есть предположение что там хитрый финт ушами и на самом деле данных больше. Но это всё хозяйство упрятали именно для того, чтобы стринг в регистр помещался.
no subject
Date: 2012-08-30 03:23 am (UTC)На Java писал довольно мало, но, IMHO, в данном конкретном случае проявлением джавизма было бы использование StringBuilder. А это для конкатенаций и массовых перемещений символов как раз таки правильный подход, который STL неплохо бы перенять.
Но не могу сказать, чтобы меня это слишком сильно волновало, тем не менее... для редких но метких оптимизаций сделать string_builder дело не то чтобы очень сложное, но опять же, надо делать...
no subject
Date: 2012-08-30 06:24 am (UTC)памятник Пушкинуты до сих пор не в комитете? (Я на самом деле только наполовину шучу, я очень согласен с твоими взглядами на C++ :-) )no subject
Date: 2012-08-30 06:45 am (UTC)Что-то я гуглением полного списка живых людей-членов комитета не найду, а из first-billed никого лично не знаю. Может, в полном списке кто из моих знакомых есть и лоббирования хватит?
no subject
Date: 2012-08-30 07:18 am (UTC)no subject
Date: 2012-09-09 06:46 am (UTC)до введения в шаблон дополнительного параметра min_alloc со значением по умолчанию, равным 1 (и с полезным на нашей практике значением порядка сотни-двух), эти архимеды, начиная то ли со Степанова, то ли со Страуструпа, не дотумкали
>>
Это они сознательно не сделали: цель стандартной библиотеки - минимально-достаточная базовая функциональность, а не "все что угодно что может кому-то понадобиться". Это Страуструп в своей книге объясняет (и это смысленно чтоб библиотека имела обозримый размер). Делайте свой класс полезный в вашей практике.
А с reserve() возвращающим ссылку на объект Вы совершенно правы, это бы им стоило сделать.
no subject
Date: 2012-09-09 06:53 am (UTC)Т.е. буквально "копируйте существующее стандартное решение и добавляйте к нему две строки, потому что кто-то когда-то решил быть чистоплюем". Это я считаю свинством.
no subject
Date: 2012-09-09 08:30 am (UTC)no subject
Date: 2012-09-09 04:16 pm (UTC)no subject
Date: 2012-09-10 05:44 am (UTC)no subject
Date: 2012-09-10 05:57 am (UTC)no subject
Date: 2012-09-10 07:26 am (UTC)Сделать свой класс derived from STL container и определить у него используемые вами конструкторы containerа с телом { reserve(min_alloc); }
no subject
Date: 2012-09-10 07:36 am (UTC)Если condition = false, foo.capacity() должна оставаться нулем.
no subject
Date: 2012-09-10 07:42 am (UTC)no subject
Date: 2012-09-10 07:57 am (UTC)no subject
Date: 2012-09-10 08:20 am (UTC)no subject
Date: 2012-09-10 08:32 am (UTC)Нет у аллокатора такого права.
no subject
Date: 2012-09-10 08:45 am (UTC)no subject
Date: 2012-09-10 08:55 am (UTC)no subject
Date: 2012-09-10 09:13 am (UTC)allocator::allocate(2^k, 0<k<7) возвращает буфер+(2^k)-1
no subject
Date: 2012-09-10 09:23 am (UTC)Если стандартный аллокатор уже так не реализован.
no subject
Date: 2012-09-10 03:15 pm (UTC)