People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
> Куда проще по старинке: > > for(int i=0;i<N;++i) > { > array[i] = i; > // > } > > > Плюс в 1-м варианте у меня нет счётчика,а здесь есть. В общем так > спокойнее — без канатоходства.
А давайте теперь заменим vector на list, а потом на set... и запишем по старинке...
Не забудьте зонтик по канату ходить.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
В одном конкретном случае зачастую проще свилосипедствовать, чем разбираться с алгоритмом STL или с особенностями контейнеров. Зачастую быстрее написать алгоритм чем искать его в справочнике (в смысле в хелпе). Кароче надо довольно длинный список в голове держать. Если, скажем, ф-я поиска подстроки есть всегда и везде, то реализовывать её самому мне в голову не придёт, а вот тотже find_if: "ХЗ — есть эта фича в STL или нет — быстрее самому написать. Может я её ещё и не запинаю в своём случае". Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
ЗЫ
Каквыпонимаете этоя спозиции новичка рассказываю. Со временем конечно появляется какое-то трудноформализуемое чутьё — навык.
Здравствуйте, Mazay, Вы писали:
M>Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
Это не в STL нет структурированности, а в твоих знаниях оной.
Здравствуйте, KBH, Вы писали:
KBH>Здравствуйте, Mazay, Вы писали:
M>>Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
KBH>Это не в STL нет структурированности, а в твоих знаниях оной.
Согласен. Только почему-то не я один такой. Наверное потому,что для того что бы сказать что функция next_permutation есть в STL это нужно просто ЗНАТЬ. Ты не можешь об этом догадаться, как например ты можешь не знать, чтоо в boost::filesystem есть функция извлечени пути из полного имени файла, но при этом логично предположить, что она там есть. И в 1-ю очередь я загляну в хелп, ибо вероятность найти там желаеме высока. А в случае с STL ДОГАДАТЬСЯ о наличии там какой-то фичи — проблематично. Если я не уверен что там есть нужный мне алгоритм,то не буду тратить время на штудирование хелпа — я напишу свой, ибо мои поиски могут не увенчаться успехом и я в пустую потрачу драгоценное время. Если конечно передо мной не стоит задача "по максимуму использовать STL".
Здравствуйте, KBH, Вы писали:
KBH>Здравствуйте, Mazay, Вы писали:
M>>Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
KBH>Это не в STL нет структурированности, а в твоих знаниях оной.
ЗЫ
Я не пытаюсь доказать что STL — отстой. Просто хочу восстановить цепочку рассуждений программиста,который пишет велосипед, вместо использовани STL. Не велосипедничают ведь при конкатенации строк. А вот к STL как то привыкнуть не могут.
Mazay wrote: > В одном конкретном случае зачастую проще свилосипедствовать, чем > разбираться с алгоритмом STL или с особенностями контейнеров.
Чего в контейнерах STL такого сложного?
> быстрее написать алгоритм чем искать его в справочнике (в смысле в > хелпе). Кароче надо довольно длинный список в голове держать. Если, > скажем, ф-я поиска подстроки есть всегда и везде, то реализовывать её > самому мне в голову не придёт, а вот тотже find_if
Как ты будешь подстроку в std::map искать?
> Нет в СТЛ какой-то структурировнности, что-ли. Какого-то > простого правила — "Вот это точно должно быть в СТЛ, а вот это — не > стоит и искать там".
STL вполне хорошо структурирована. Надо просто понимать идеологию
итераторов — тогда все становится просто и понятно.
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
У STL много минусов (про некоторые из них можно поискать на форуме), но главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального). Конкретные реализации тоже плохо эволюционируют и не в том направлении. Фактически мы имеем дело с мертвой вещью. Ближайший аналог -- MFC.
Использовать мертвую вещь для новых проектов не стоит.
Теперь более конкретно.
1) STL это библиотека алгоритмов и контейнеров.
2) Какие алгоритмы есть в этой библиотеке? Из серьёзных и востребованых -- sort, stable_sort, heap_sort . Всё остальное -- не алгоритмы, а мелкие утилиты, в большинстве бесполезные (типа знаменитого for_each).
sort, stable_sort
Что это за алгоритмы? А никто не знает -- произвол реализации. Хотя в том же Кнуте вагон алгоритмов сортировки.
И библиотека, претендующая на стандартную должна не фиг знает что содержать, а чисто конкретно -- sort 2, sort 3, sort 4, ..., quick sort, merge sort,
intro sort, quick random pivot sort и.т.д.
3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. Причем совершенно непонятно, зачем такое ограничение. Никаких технических причин для этого нет. Сами контейнеры. Практически единственный мало-мальски полезный класс -- vector. А где списки? Я знаю много разных типов списков. Где они все? А где деревья? RB-tree AVL-tree B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
_>А давайте теперь заменим vector на list, а потом на set... и запишем по старинке... _>Не забудьте зонтик по канату ходить.
template<class Container>
void doing_some_complex(Container& c)
{
...//здесь у нас контекст
Container::iterator i=c.begin(),endi=c.end();
for(;i!=endi;++i)
{
...//а здесь мы его используем
}
...
}
Проблема не в том как вы обходите контейнер, а в том что писать
функциональный объект (или отдельную функцию) фактически для тела for()
оказывается непрактично
За всё время я наверное раза 2 использовал for_each()
Здравствуйте, Cyberax, Вы писали:
C>Mazay wrote: >> В одном конкретном случае зачастую проще свилосипедствовать, чем >> разбираться с алгоритмом STL или с особенностями контейнеров. C>Чего в контейнерах STL такого сложного?
По отдельности — ничего. А вот в целом... Ну почему рядом с map я не нахожу hashmap ? Ну и есть ещё грабли с vector<bool>.
>> быстрее написать алгоритм чем искать его в справочнике (в смысле в >> хелпе). Кароче надо довольно длинный список в голове держать. Если, >> скажем, ф-я поиска подстроки есть всегда и везде, то реализовывать её >> самому мне в голову не придёт, а вот тотже find_if C>Как ты будешь подстроку в std::map искать?
Не, я имел ввиду то, что я никогда не стану писать функцию поиска подстроки в строке, ибо уверен что всё придумано до нас. А вот наличие find_if'a для меня стало приятной неожиданностью.
>> Нет в СТЛ какой-то структурировнности, что-ли. Какого-то >> простого правила — "Вот это точно должно быть в СТЛ, а вот это — не >> стоит и искать там". C>STL вполне хорошо структурирована. Надо просто понимать идеологию C>итераторов — тогда все становится просто и понятно.
Понимание идеологии итераторов не даст мне знание всех алгоритмов библиотеки. Их надо просто вызубрить. Ну хотя бы запомнить что алгоритм дл такой-то задачи там точно есть.
Блин, а давайте ещё поспорим на тему "Какие недостатки у С++"
Уверен, ответы будут:
"Я плохо, понимаю С++" ->
"Для того чтобы хорошо знать С++, нужно прочитать много книг, и осознать то, что в них написано" -> "C++ слишком сложный" -> "Нафига мне нужен такой язык?" -> "возьму я Basic, или ещё лучше напишу свой"
Здравствуйте, Cyberax, Вы писали:
C>Mazay wrote: >> В одном конкретном случае зачастую проще свилосипедствовать, чем >> разбираться с алгоритмом STL или с особенностями контейнеров. C>Чего в контейнерах STL такого сложного?
Создатели библиотеки предпочитали вообще не реализовывать некоторые вещщие, если не были уверены в том, что penalty будет минимальным. Естессно такое бывает только в сказках — в результате библиотека создаёт впечатление недоделанной, фрагментированной. Как будто собрались старые приятели и склеили свои велосипеды в одну библиотеку. Что-то есть — хорошо, нет — сами пишите. Благо общее направление движения задано верно: я предпочту написать свой класс, так чтоб он выглядел как часть STL и легко с ней интегрировался.
Здравствуйте, Шахтер, Вы писали:
Ш>У STL много минусов (про некоторые из них можно поискать на форуме), но главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального). Конкретные реализации тоже плохо эволюционируют и не в том направлении. Фактически мы имеем дело с мертвой вещью. Ближайший аналог -- MFC.
Что-то больно мрачно. Ш>Использовать мертвую вещь для новых проектов не стоит. Ш>Теперь более конкретно.
Ш>1) STL это библиотека алгоритмов и контейнеров. Ш>2) Какие алгоритмы есть в этой библиотеке? Из серьёзных и востребованых -- sort, stable_sort, heap_sort . Всё остальное -- не алгоритмы, а мелкие утилиты, в большинстве бесполезные (типа знаменитого for_each).
Ш>sort, stable_sort
Ш>Что это за алгоритмы? А никто не знает -- произвол реализации. Хотя в том же Кнуте вагон алгоритмов сортировки. Ш>И библиотека, претендующая на стандартную должна не фиг знает что содержать, а чисто конкретно -- sort 2, sort 3, sort 4, ..., quick sort, merge sort, Ш>intro sort, quick random pivot sort и.т.д.
+1
Ш>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. Причем совершенно непонятно, зачем такое ограничение. Никаких технических причин для этого нет. Сами контейнеры. Практически единственный мало-мальски полезный класс -- vector. А где списки? Я знаю много разных типов списков. Где они все? А где деревья? RB-tree AVL-tree B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
Ш>Короче. Диагноз -- халтура. Два балла.
Жёстко! Хотя я согласен: если делаете библиотеку контейнеров — так делайте её до конца. Даже если что-то будет не очень эффективно никто не мешает пользовтелям отнаследоваться или специализировать шаблон.
Каждый раз натыкаюсь, и каждый раз матерюсь.
Бывает надо написать обощённый класс, который возвращает ссылку на тип,
а контейнер там vector и надо вдруг bool использовать...
... и начинаются подпорки ввиде специализаций и замены
внутреннего типа на какой-нибудь char
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
1) Контейнеры STL не транзакционны. Т.е. если во время операции с контейнером не удалось выделить память, то после этого контейнер находится в неопределнном состоянии — уже не исходное, но еще не конечное. Соответственно типы, которые хранят данные в STL контейнерах тоже не будут транзакционными, если не прилагать специальных усилий и терять при этом эффективность.
2) В случае невозможности выделения памяти контейнеры STL кидают исключение. Стало быть, вызывающий код обязан его обрабатывать. Если вы используете STL в программе, это не так страшно, а вот если пишете библиотеку ф-ций с использованием STL, то тем самым навязываете пользователю то, что он тоже должен обрабатывать исключения. Если Вы используете контейнеры только внутренне и аккуратно обрабатываете все исключения, то тогда еще не все потеряно. А вот если используете типы STL в параметрах ф-ций, тогда плохо дело.
Насколько я знаю, STL, который поставляется с Visual Studio эти недостатки имеет. Было бы интересно узнать, как обстоит дело в остальных реализациях.
А вообще очень красивая библиотека. Лично мне нравится, только из-за вышеперечисленного пользоваться ей нужно очень осторожно.
G>1) Контейнеры STL не транзакционны. Т.е. если во время операции с контейнером не удалось выделить память, то после этого контейнер находится в неопределнном состоянии — уже не исходное, но еще не конечное. Соответственно типы, которые хранят данные в STL контейнерах тоже не будут транзакционными, если не прилагать специальных усилий и терять при этом эффективность.
Не совсем правда. Насколько я помню.
Контейнеры гарантируют компромисс, что выделенная память не будет потеряна, если произошло
исключение, при выделении памяти.
Но транзакционность, т.е. откат в состояние до начала операции, действительно не гарантируют.
Шахтер wrote: > Где они все? А где деревья? RB-tree AVL-tree > B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
В Boost'е А еще в STL из полезных вещей есть map, string. В принципе,
больше особо ничего и не использую оттуда.
> Короче. Диагноз -- халтура. Два балла.
Вполне нормальная библиотека, ее достоинство в том, что она продвинула в
массу идею разделения алгоритмов и контейнеров.
Mazay wrote: > C>Чего в контейнерах STL такого сложного? > По отдельности — ничего. А вот в целом... Ну почему рядом с map я не > нахожу hashmap ? Ну и есть ещё грабли с vector<bool>.
hashmap просто не успели добавить в Стандарт. Добавят в следующий Стандарт.
> C>Как ты будешь подстроку в std::map искать? > Не, я имел ввиду то, что я никогда не стану писать функцию поиска > подстроки в строке, ибо уверен что всё придумано до нас. А вот наличие > find_if'a для меня стало приятной неожиданностью.
Ну так методы поиска подстроки же есть.
Хотя я бы обобщил его в алгоритм "find_sequence(Start, Stop,
SeqStart,SeqStop)".
> C>STL вполне хорошо структурирована. Надо просто понимать идеологию > C>итераторов — тогда все становится просто и понятно. > Понимание идеологии итераторов не даст мне знание всех алгоритмов > библиотеки. Их надо просто вызубрить. Ну хотя бы запомнить что алгоритм > дл такой-то задачи там точно есть.
Так какие проблемы? Все алгоритмы стандартной библиотеки умещаются в
пару колонок на листе A4. И в поиске по документации ищутся за секунду.
Mazay wrote: >> > В одном конкретном случае зачастую проще свилосипедствовать, чем >> > разбираться с алгоритмом STL или с особенностями контейнеров. > C>Чего в контейнерах STL такого сложного? > Создатели библиотеки предпочитали вообще не реализовывать некоторые > вещщие, если не были уверены в том, что penalty будет минимальным.
Примеры?
ghostrider wrote: > 1) Контейнеры STL не транзакционны. Т.е. если во время операции с > контейнером не удалось выделить память, то после этого контейнер > находится в неопределнном состоянии — уже не исходное, но еще не > конечное. Соответственно типы, которые хранят данные в STL контейнерах > тоже не будут транзакционными, если не прилагать специальных усилий и > терять при этом эффективность.
Для контейнеров есть несколько операций, для которых гарантирована
"транзакционность" (strong exception guarantee). Ими и надо пользоваться.
А написать транзакционный контейнер в общем случае все равно не получится.
> 2) В случае невозможности выделения памяти контейнеры STL кидают > исключение. Стало быть, вызывающий код обязан его обрабатывать. Если вы > используете STL в программе, это не так страшно, а вот если пишете > библиотеку ф-ций с использованием STL, то тем самым навязываете > пользователю то, что он тоже должен обрабатывать исключения. Если Вы > используете контейнеры только внутренне и аккуратно обрабатываете все > исключения, то тогда еще не все потеряно. А вот если используете типы > STL в параметрах ф-ций, тогда плохо дело.
А что, кто-то еще передает контейнеры в функции не по константной ссылке?
C>А что, кто-то еще передает контейнеры в функции не по константной ссылке?
А причем тут константность ссылки? Она кстати может быть и неконстантная, если функция будет менять содеаржимое. Проблема в другом — используя тип в качестве параметра, ты заставляешь пользователя пользоваться этим типом и пожинать все последствия. Ситуация усугубляется тем, что этот тип определяешь не ты, так что полностью контролировать его поведение не можешь.
Здравствуйте, Шахтер, Вы писали:
Ш>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. Причем совершенно непонятно, зачем такое ограничение. Никаких технических причин для этого нет. Сами контейнеры. Практически единственный мало-мальски полезный класс -- vector. А где списки? Я знаю много разных типов списков. Где они все? А где деревья? RB-tree AVL-tree B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
Контейнеры указателей, контейнеры объектов со счетчиками ссылок, контейнеры некопирабельных типов (если я правильно это понимаю) — я сам себе написал и с 2000 года горя не знаю В виде надстройки над std::vector.
Деревья в чистом виде, не знаю зачем мне могли бы понадобиться ... но шаблоны для них и, в конечном итоге, AVL-дерево у меня есть. Единственным основанием существования этого дерева является наличие template-member-ов
1. Всё то чего нет в текущей версии stl (прошу меня простить но почемуто под STL имею в виду С++ Standart Library ) но будет в следующей.
2. Это то что stl не охватывает все области... например нет сокетов, threads, GUI, баз данных
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Проблема не в том как вы обходите контейнер, а в том что писать ШЕ>функциональный объект (или отдельную функцию) фактически для тела for() ШЕ>оказывается непрактично ШЕ>За всё время я наверное раза 2 использовал for_each()
ШЕ>Хотя из этого не следует что он не нужен.
Например в комбинации со всяческими биндерами бывает крайне полезен
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ> Блин, а давайте ещё поспорим на тему "Какие недостатки у С++"
1) Очень сложный язык, очень гибкий, с нереально сложным синтаксисом. Это приводит к тому, что для коллективного программирования на C++ абсолютно необходима инструкция.
А для написания хорошего компилятора нужен довольно большой НИИ
2) Язык C++ очень плохо изолирует программиста от очень низкого уровня. AV, привязка к определённому endian, зависимость от размеров типов, от их выравнивания и т. д. и т. п. -- соверщенно неизбежны при программировании на C++. Для многих задачь это таки лишнее.
3) Провоцирует использование сверхсложных шаблонных конструкций. При чём часто совершенно не по делу.
4) Огромная перегруженность всех механизмов языка. Например:
4а) классы используются для создания типов, похожих на встроенные, для ООП, для реализации парадигмы COM (интерфейсы + объектная модель), для реализации механизмов, для всяких синтаксических трюков и много для чего ещё.
4б) Наследование. Используется для ООП, для выражение отношения "реализует интерфейс", для callbacks (особенно в механизмах распространено), для всяких синтаксических трюков (скажем класс allocated_in_virtual_memory) и опять же много для чего ещё.
Это всё приводит к тому, что часто при чтении программы, особенно чужой и написанной по неизвестнйо тебе инструкции, ты не можешь понять какой именно концепт выражен этой конструкцией языка
Хватит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
Так как изделие шаблонное, то оно всюду компилируется заново, поэтому, если вы делаете библиотеку на STL, то вы навязываете пользователю своей библиотеки версию STL, что не всегда удобно пользователям.
Ну, или, вы должны опубликовать свои исхдники и обеспечить работоспособность библиотеки с любой реализацией STL, что тоде небанально. Особенно в области тестирования изделия
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Так как изделие шаблонное, то оно всюду компилируется заново, поэтому, если вы делаете библиотеку на STL, то вы навязываете пользователю своей библиотеки версию STL, что не всегда удобно пользователям.
E>Ну, или, вы должны опубликовать свои исхдники и обеспечить работоспособность библиотеки с любой реализацией STL, что тоде небанально. Особенно в области тестирования изделия
Если не использовать не стандартные расширения конкретных реализаций то проблем переноса с одной версии на другу нет, если конечно переносить на соответствующие стандарту реализации
Здравствуйте, gid_vvp, Вы писали:
_>Если не использовать не стандартные расширения конкретных реализаций то проблем переноса с одной версии на другу нет, если конечно переносить на соответствующие стандарту реализации
1) А как тестировать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>Думаю что stl тестировать не надо _>А библиотеку на основе stl можно тестировать на одной реализации
А где гарантии?
Например, где гарантии, что нигде не заложлись на особенность реализации?
Например на производительность какого-нибудь метода?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Cyberax, Вы писали:
C>Шахтер wrote: >> Где они все? А где деревья? RB-tree AVL-tree >> B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило. C>В Boost'е А еще в STL из полезных вещей есть map, string. В принципе, C>больше особо ничего и не использую оттуда.
>> Короче. Диагноз -- халтура. Два балла. C>Вполне нормальная библиотека, ее достоинство в том, что она продвинула в C>массу идею разделения алгоритмов и контейнеров.
Шахтер wrote: >> > Короче. Диагноз -- халтура. Два балла. > C>Вполне нормальная библиотека, ее достоинство в том, что она продвинула в > C>массу идею разделения алгоритмов и контейнеров. > Боюсь что на этом её достоинства и исчерпываются.
Мне этого вполне достаточно — свою библиотеку контейнеров я уже написал
M> Плюс в 1-м варианте у меня нет счётчика,а здесь есть. В общем так спокойнее — без канатоходства.
Насколько хорошо вы комментируте код? Такое ощущение, что перед данным циклом у вас одна запись типа: "делаем то-то и то-то".
У цикла есть собственная семантика, а у вас какая-то "вещь в себе" получается.
24 августа 2006 11:36 gid_vvp wrote:
> на мой взгляд вырисовалось ещё два минуса...
Взгляд у вас костный. Привязан, видимо, к логотипу сломанного окна...
> 2. Это то что stl не охватывает все области... например нет сокетов, > threads, GUI, баз данных
И как GUI жить на embedded-железе, у которого единственный информационный
интерфейс наружу — это подключенный к компорту терминал? А база данных
должна иметь триггеры, ХП, репликацию? )
v_m> Взгляд у вас костный. Привязан, видимо, к логотипу сломанного окна...
Уважаемый давайте не будем обсуждять у кого какой взгляд?
>> 2. Это то что stl не охватывает все области... например нет сокетов, >> threads, GUI, баз данных v_m> И как GUI жить на embedded-железе, у которого единственный информационный v_m>интерфейс наружу — это подключенный к компорту терминал?
ничего не мешает этому GUI быть в библиотеке в общем случае и для поддерживающих систем и не быть для неподдерживающих систем.
хотя обощённое гуи это не простая задача, но есть множество примеров
v_m> А база данных v_m>должна иметь триггеры, ХП, репликацию? )
Шебеко Евгений wrote:
> Проблема не в том как вы обходите контейнер, а в том что писать > функциональный объект (или отдельную функцию) фактически для тела for() > оказывается непрактично > За всё время я наверное раза 2 использовал for_each()
Ты вроде сравнивал:
for(vector<int>::iterator it = array.begin();it!=array.end();++it)
и
for(int i=0;i<N;++i)
... причём тут for_each? Просто я предпочитаю первый вариант в большинстве случаев, ибо более универсален.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
ИМХО, самый большой недостаток — плохо продуманная структура...
Если последовательные контейнеры еще ничего (хотя почему вектор назвали вектором, а не array — никак не пойму),
то ассоциативные — оставляют желать лучшего...
Подчеркивание того, что множество — ассоциативный контейнер — только с толку сбивает начинающего...
Множество — это множество, как бы оно ни было реализовано...
Подчеркивать специфику реализации не стоило и для map — можно было б и как хеш реализовать...
А набор алгоритмов — это вообще напорминает свалку...
А уж про string все написал Саттер в последней книжке — интерфейс перегружен до предела...
Битовый вектор можно было сделать и динамическим...
И похоже на то, что новой редакции STL мы не скоро дождемся... Тока вместе со стандартом...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
LaptevVV wrote:
> _>перечислите, на ваш взгляд, основные минусы STL > _>принимаются только ответы с аргументацией > ИМХО, самый большой недостаток — плохо продуманная структура...
В голове у начинающих программистов?
> Если последовательные контейнеры еще ничего (хотя почему вектор назвали > вектором, а не array — никак не пойму),
Потому что одномерный array называется vector, двухмерный array называется matrix. Трёх и более специальных названий не
имеют (насколько я знаю).
> то ассоциативные — оставляют желать лучшего... > Подчеркивание того, что множество — ассоциативный контейнер — только с > толку сбивает начинающего...
It is a simple associative container because its element values are its key values.
Просто это так. Что не устраивает?
К тому же, можно множества одних и тех же элементов строить, но с разным operator<, что в итоге может давать разные
множества.
> Множество — это множество, как бы оно ни было реализовано... > Подчеркивать специфику реализации не стоило и для map — можно было б и
А если для объекта хаш считать очень неудобно или получится неэффективно?
> как хеш реализовать...
std::hash_map?
> А набор алгоритмов — это вообще напорминает свалку... > А уж про string все написал Саттер в последней книжке — интерфейс > перегружен до предела...
С этим согласен.
> Битовый вектор можно было сделать и динамическим...
Не понял? std::vector<bool>? А он какой?
> И похоже на то, что новой редакции STL мы не скоро дождемся... Тока > вместе со стандартом...
Юзаем boost, и хватит плакаться.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan_izh, Вы писали:
_>LaptevVV wrote:
>> _>перечислите, на ваш взгляд, основные минусы STL >> _>принимаются только ответы с аргументацией >> ИМХО, самый большой недостаток — плохо продуманная структура... _>В голове у начинающих программистов?
>> Если последовательные контейнеры еще ничего (хотя почему вектор назвали >> вектором, а не array — никак не пойму), _>Потому что одномерный array называется vector, двухмерный array называется matrix. Трёх и более специальных названий не _>имеют (насколько я знаю).
Здравствуйте, gid_vvp, Вы писали:
E>>А где гарантии? E>>Например, где гарантии, что нигде не заложлись на особенность реализации? E>>Например на производительность какого-нибудь метода?
_>все гарантии в стандарте...
При чём тут стандарт?
Вот ты разрабатываешь большую коммерческую библиотеку. Вот тебе как-то надо обеспечить качество разработки. Ты для этого проводишь ревизию кода и тестирование.
Ну и где гарантии? Ревизия кода дело долгое, высококвалифицированное и не осчень надёжное
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
LaptevVV,
> Подчеркивание того, что множество — ассоциативный контейнер — только с толку сбивает начинающего...
Или, с другой стороны, дает ему в руки более общую "модельку", которая позволит легко запомнить общие моменты set, multiset, bitset, map и multimap без запоминания всех их деталей как было бы, будь они несвязанными компонентами.
> Подчеркивать специфику реализации не стоило и для map — можно было б и как хеш реализовать...
Гм... В чем, интересно, состояло подчеркивание специфики реализации? А при реализации в виде hash изменилась бы семантика, т.к. порядок перестал бы быть определенным.
> Битовый вектор можно было сделать и динамическим...
Можно. vector<bool> и так динамический.
> И похоже на то, что новой редакции STL мы не скоро дождемся... Тока вместе со стандартом...
Это неизбежное следствие её стандартизации.
Posted via RSDN NNTP Server 2.0
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Шахтер, Вы писали:
Ш>главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального).
Верно, (но) это вынужденная мера. Либо иметь 68 велосипедов, либо какой-никакой, но стандарт. Да, из-за этого ценность снижена, но и цена использования тоже. Промышленный накладывает свои отпечатки.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
25 августа 2006 10:57 gid_vvp wrote:
> информационный v_m>интерфейс наружу — это подключенный к компорту > терминал? > ничего не мешает этому GUI быть в библиотеке в общем случае и для > поддерживающих систем и не быть для неподдерживающих систем. хотя > обощённое гуи это не простая задача, но есть множество примеров
Зачем в стандартной обвязке какая-то библиотека для частного случая? Тем
более, библиотек для gui вагон с тележкой, какую же конкретно надо
использовать, чтобы всех удовлетворить?
> v_m> А база данных > v_m>должна иметь триггеры, ХП, репликацию? ) > почему нет?
Тот же самый вопрос, что и с gui.
v_m> Зачем в стандартной обвязке какая-то библиотека для частного случая? Тем v_m>более, библиотек для gui вагон с тележкой, какую же конкретно надо v_m>использовать, чтобы всех удовлетворить?
E>При чём тут стандарт? E>Вот ты разрабатываешь большую коммерческую библиотеку. Вот тебе как-то надо обеспечить качество разработки. Ты для этого проводишь ревизию кода и тестирование. E>Ну и где гарантии? Ревизия кода дело долгое, высококвалифицированное и не осчень надёжное
Обычно пишу много-много тестов и прогоняю их в том числе на разных версиях библиотек (это относится не только к STL)
26 августа 2006 14:53 gid_vvp wrote:
> v_m> Зачем в стандартной обвязке какая-то библиотека для частного случая? > Тем v_m>более, библиотек для gui вагон с тележкой, какую же конкретно надо > v_m>использовать, чтобы всех удовлетворить? > Что за вопросы? > Несомненно лучшую
Например?
Здравствуйте, gid_vvp, Вы писали:
E>>Ну и где гарантии? Ревизия кода дело долгое, высококвалифицированное и не осчень надёжное
_>Обычно пишу много-много тестов и прогоняю их в том числе на разных версиях библиотек (это относится не только к STL)
Имеются в виду автоматические тесты готового изделия? И при этом ещё подразумевается воссоздание всех разнообразных условий компиляции и версий STL ?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Имеются в виду автоматические тесты готового изделия? И при этом ещё подразумевается воссоздание всех разнообразных условий компиляции и версий STL ?
27 августа 2006 15:40 gid_vvp wrote:
>>> Несомненно лучшую > v_m> Например? > незнаю я гуйню не пишу... > например qt... когда станет свободной
билл гейтс будет против
Здравствуйте, gid_vvp, Вы писали:
E>>Имеются в виду автоматические тесты готового изделия? И при этом ещё подразумевается воссоздание всех разнообразных условий компиляции и версий STL ? _>всех это уже маразм _>обычно ищетсяя компромис
всех -- это всех встречающихся у пользователей
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
если удаётся сделать это (за что надо поставить отдельный памятник тому кто может предусмотреть всех встречающихся у пользователей), то количество тестов не на много возрастает в связи с использованием разных stl
Здравствуйте, kan_izh, Вы писали:
>> ИМХО, самый большой недостаток — плохо продуманная структура... _>В голове у начинающих программистов?
Начинающих юзать STL _>Потому что одномерный array называется vector, двухмерный array называется matrix. Трёх и более специальных названий не имеют (насколько я знаю).
Лично у меня векторы и матрицы ассоциируются исключительно с математикой...
Одномерный массив — не обязательно вектор... Для вектора в n-мерном пространстве характерно вычисление длины...
>> то ассоциативные — оставляют желать лучшего... >> Подчеркивание того, что множество — ассоциативный контейнер — только с >> толку сбивает начинающего... _>It is a simple associative container because its element values are its key values. _>Просто это так. Что не устраивает? _>К тому же, можно множества одних и тех же элементов строить, но с разным operator<, что в итоге может давать разные _>множества.
Множество, вообще-то, неупорядоченная структура... Искусственно ее упорядочивать — это с толку и сбивает... >> Подчеркивать специфику реализации не стоило и для map — можно было б и _>А если для объекта хаш считать очень неудобно или получится неэффективно?
Не... Хеш — всегда феективней дерева... Просто нужно хеш-функцию подобрать... Вот и порылись бы — столько лет стандарт разрабатывали...
Хотя для map, как правильно заметил Павел Кузнецов ниже — естественная упорядоченность может пригодиться... _>std::hash_map?
Дык его и забыли включить, как пишет Страуструп... И опять же — зачем специфику реализации подчеркивать...
Идея ж — как раз абстрагироваться от реализации, а в STL эти уши торчат из всех щелей... >> А набор алгоритмов — это вообще напорминает свалку... >> А уж про string все написал Саттер в последней книжке — интерфейс >> перегружен до предела... _>С этим согласен.
>> Битовый вектор можно было сделать и динамическим... _>Не понял? std::vector<bool>? А он какой?
Тока операций в нем нифига не реализовано по сравнению с bitset...
>> И похоже на то, что новой редакции STL мы не скоро дождемся... Тока >> вместе со стандартом... _>Юзаем boost, и хватит плакаться.
boost — вообще вся похожа на свалку...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Павел Кузнецов, Вы писали:
>> Подчеркивание того, что множество — ассоциативный контейнер — только с толку сбивает начинающего... ПК>Или, с другой стороны, дает ему в руки более общую "модельку", которая позволит легко запомнить общие моменты set, multiset, bitset, map и multimap без запоминания всех их деталей как было бы, будь они несвязанными компонентами.
Ну, это да... Интерфейс практически один в один (кроме битсета)... Но ведь идея-то — абстрагироваться от конкретной реализации, а в STL эти уши торчаит из всех щелей... >> Подчеркивать специфику реализации не стоило и для map — можно было б и как хеш реализовать... ПК>Гм... В чем, интересно, состояло подчеркивание специфики реализации? А при реализации в виде hash изменилась бы семантика, т.к. порядок перестал бы быть определенным.
Ну, вот с этим действительно можно согласиться... Не могу сходу придумать, но скорее всего естественная сортировка может пригодиться... >> Битовый вектор можно было сделать и динамическим... ПК>Можно. vector<bool> и так динамический.
Тока операций в нем мало... >> И похоже на то, что новой редакции STL мы не скоро дождемся... Тока вместе со стандартом... ПК>Это неизбежное следствие её стандартизации.
Ну, эт понятно...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
>>> то ассоциативные — оставляют желать лучшего... >>> Подчеркивание того, что множество — ассоциативный контейнер — только с >>> толку сбивает начинающего...
LVV>Множество, вообще-то, неупорядоченная структура... Искусственно ее упорядочивать — это с толку и сбивает...
Кстати, а чем отличается множество от того же массива (вектора)? Тем, что в векторе элементы лежат в одном порядке, а во множестве — порядок не определён? Или как? Я вот тоже не понимаю std::set<>.
Здравствуйте, IceStudent, Вы писали:
LVV>>Множество, вообще-то, неупорядоченная структура... Искусственно ее упорядочивать — это с толку и сбивает... IS>Кстати, а чем отличается множество от того же массива (вектора)? Тем, что в векторе элементы лежат в одном порядке, а во множестве — порядок не определён? Или как? Я вот тоже не понимаю std::set<>.
Вообще, если трактовать std::vector<bool> как множество чисел (то есть в множестве есть те из чисел, для которых вектор сожержит true), то порядок тоже не определён.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
IceStudent wrote:
> LVV>Множество, вообще-то, неупорядоченная структура... Искусственно ее > упорядочивать — это с толку и сбивает... > Кстати, а чем отличается множество от того же массива (вектора)? Тем, > что в векторе элементы лежат в одном порядке, а во множестве — порядок > не определён? Или как? Я вот тоже не понимаю std::set<>.
std::set почти тоже самое, что и std::map, но ключ и значение — один и тот же объект (или можно ещё сказать, что
значение всегда эквивалентно ключу). А значит как минимум нужен operator<() для типа. Соответственно, std::set элементы
упорядочены в соответствии с operator<().
Если сравнивать с java.util.Set, то аналогом будет std::hash_set, а аналога std::set в яве, насколько я знаю, нет.
Ну а std::vector — банальный одномерный массив. Больше ничего.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, pavel_turbin, Вы писали:
_>Здравствуйте, Шахтер, Вы писали:
Ш>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус.
_>это элементарно обходится: используй контейнеры на SmartPtr, а сам указатель может быть и некопирабельным.
И аллокировать каждый объект в динамической памяти?
Нет, спасибо.
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, Шахтер, Вы писали:
Ш>>главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального).
GN>Верно, (но) это вынужденная мера. Либо иметь 68 велосипедов, либо какой-никакой, но стандарт. Да, из-за этого ценность снижена, но и цена использования тоже. Промышленный накладывает свои отпечатки.
Промышленный -- не значит плохой.
А если значит -- ну его на фик.
Шахтер wrote:
> Ш>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. > Это огромный минус. > > _>это элементарно обходится: используй контейнеры на SmartPtr, а сам > указатель может быть и некопирабельным. > > > И аллокировать каждый объект в динамической памяти? > Нет, спасибо.
А как ты тогда себе представляешь динамический массив без возможности скопировать элемент?
Вроде только если будут move constructor... это обещают в следующей версии языка... но...
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
G>2) В случае невозможности выделения памяти контейнеры STL кидают исключение. Стало быть, вызывающий код <b>обязан</b> его обрабатывать.
ничего он не обязан. как часто вызывающий код может корректно обработать такую ситуацию? практически никогда.
имхо, страуструп абсолютно прав, предлагая (или, скорее, считая что) использовать исключения (обрабатывать их) не в рамках одного модуля, а на границах модулей, где действительно можно решить данную проблему — например, отключить какую-то функциональность.
у нас в проекте во многих местах есть проверки, что malloc вернет ноль — это лишь откладывает ошибку на некоторое (не такое уж и большое время), а если разрабатывать суперстабильную систему, то все равно нужно как-то обрабатывать подобные исключительные ситуации (тогда какая разница: поймать исключение или проверить результат функции?)... а может вообще vector, например, должен _молча_ выделить столько, сколько сможет и все?!
Не все в этом мире можно выразить с помощью нулей и единиц...
kan_izh wrote: >> И аллокировать каждый объект в динамической памяти? >> Нет, спасибо. > А как ты тогда себе представляешь динамический массив без возможности > скопировать элемент?
Элементы можно перемещать. Даже сейчас, смотри, например, http://www.ddj.com/dept/cpp/184403855
> Вроде только если будут move constructor... это обещают в следующей > версии языка... но...
Ну так я свою библиотеку контейнеров вроде написал
E>если вы делаете библиотеку на STL, то вы навязываете пользователю своей библиотеки версию STL, что не всегда удобно пользователям.
Дык тут проблема не в STL, а в С++ в целом. Вернее, даже не в С++ — а в том что внутри не-managed кода сделать написание межмодульных интерфейсов простым и удобным в общем случае невозможно. В какой-то мере эти задачи пытаются решать на уровне middleware (COM или Corba) — но и в том и в другом случае это попытка скрестить ежа с ужом (к примеру — COM вообще жертвует исключениями в пользу поддержки языков без оных, Corba исключения поддерживает, но юзать её из языков без оных становится занятием для мозахистов).
Здравствуйте, Cyberax, Вы писали:
C>kan_izh wrote: >>> И аллокировать каждый объект в динамической памяти? >>> Нет, спасибо. >> А как ты тогда себе представляешь динамический массив без возможности >> скопировать элемент? C>Элементы можно перемещать. Даже сейчас, смотри, например, C>http://www.ddj.com/dept/cpp/184403855
Перенести указатель внутрь структуры? Но при этом все данные все-равно
в динамической памяти находятся %).
Только при этом еще теряется семантика значения.
Здравствуйте, kan_izh, Вы писали:
_>Шахтер wrote:
>> Ш>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. >> Это огромный минус. >> >> _>это элементарно обходится: используй контейнеры на SmartPtr, а сам >> указатель может быть и некопирабельным. >> >> >> И аллокировать каждый объект в динамической памяти? >> Нет, спасибо. _>А как ты тогда себе представляешь динамический массив без возможности скопировать элемент? _>Вроде только если будут move constructor... это обещают в следующей версии языка... но...
Некопируемые типы в векторе неуместны, так же как копируемые в node-based контейнерах (map,list)
Более того node-based контейнеры по хорошему должны быть интрузивными, в противном случае они не юзабельные.
Cyberax wrote:
>> > И аллокировать каждый объект в динамической памяти? >> > Нет, спасибо. >> А как ты тогда себе представляешь динамический массив без возможности >> скопировать элемент? > Элементы можно перемещать. Даже сейчас, смотри, например, > http://www.ddj.com/dept/cpp/184403855
Мда уж... Компилятор жалко. Нельзя же так над зверушкой издеваться... гринписа на таких как он и прочих бустовцев нет!
>> Вроде только если будут move constructor... это обещают в следующей >> версии языка... но... > Ну так я свою библиотеку контейнеров вроде написал
А почему невозможно написать свою имплементацию stl, полностью удовлетворяющую стандарту, но со всеми этими mojo и
прочими оптимизациями типа временных string-буферов для str1+str2+...+strN?
Ведь, как я понял, эти mojo-enabled классы вполне будут работать со "старым" кодом, который не "mojo-aware", просто
по-старинке, т.е. медленее из-за временных объектов.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Kluev wrote:
>> > И аллокировать каждый объект в динамической памяти? >> > Нет, спасибо. > _>А как ты тогда себе представляешь динамический массив без возможности > скопировать элемент? > _>Вроде только если будут move constructor... это обещают в следующей > версии языка... но... > Некопируемые типы в векторе неуместны, так же как копируемые в > node-based контейнерах (map,list) > Более того node-based контейнеры по хорошему должны быть интрузивными, в > противном случае они не юзабельные.
Ну это скоро в бусте появится, скорее всего: http://www.boost.org/more/report-jan-2006.html "Intrusive Containers". Но
скачать и использовать уже можно.
И в след. версии языка тоже рассматривают.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Nose, Вы писали:
N>Здравствуйте, Константин Л., Вы писали:
КЛ>>Здравствуйте, kan_izh, Вы писали:
КЛ>>тензоры
N>ну уж нет тензор это не просто упорядоченный набор чисел -- он еще должен подчиняться определенным правилам при смене системы координат
N>И количество имрений тут тоже ни причем, т.к. скаляр например -- частный случай тензора
Здравствуйте, Какая разница, Вы писали:
КР>Здравствуйте, gid_vvp, Вы писали:
_>>Hi All
_>>перечислите, на ваш взгляд, основные минусы STL _>>принимаются только ответы с аргументацией
КР>мое имхо — зачем там нужен std::valarray ? КР>кто-то его реально юзает? КР>есть ли от него польза?
Предполагалось, что это будет библиотека для работы с многомерными массивами, реализованная максимально эффективно... В частности, обработка матриц там есть... Однако, как заметил, кажется Джосаттис, люди, работавшие над этой библиотекой, давно ушли и занялись другими делами, поэтому библиотека брошена...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, shank, Вы писали:
S>Не надо далеко ходить... Нет способа преобразовать число в std::string и обратно. Так, чтобы было одновременно быстро, удобно и безопасно.
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
1. Все STL-контейнеры требуют копируемость элементов. Но часто объекты в программе обладают идентичностью. Неявное копирование для них бессмысленно, а потому запрещено. Чтобы хранить такие объекты в STL-контейнере, их обычно создают динамически (new), а в контейнер помещают указатели (обычные или умные, как boost::shared_ptr). Но было бы лучше (по скорости работы программы и по расходу памяти) избежать такой косвенности. В будущем это вполне возможно, если node-based контейнеры (list, map) научатся инициализировать элементы значением произвольного типа (а не только 'const value_type&', как сейчас). Тогда можно будет писать:
Когда-то давно обобщённый push_back планировался, но был отвергнут из-за слабой поддержки member templates тогдашними компиляторами. Сейчас с этим гораздо лучше.
Также был бы удобен push_back без параметров, инициализирующий новый элемент конструктором по умолчанию.
Проблему упомянули Шахтер здесь
2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция дорога. Например, нужно вывести список строк на консоль:
void PrintItems(const list<string>& Items)
{
for (list<string>::const_iterator it = Items.begin(); it != Items.end(); ++it)
{
cout << *it << '\n';
}
}
Этот код работает нормально. Но если программист забудет '&' после 'const list<string>', то список будет передаваться уже не по ссылке, а по значению. При этом программа будет компилироваться без предупреждений и правильно работать. Лишнее копирование списка может остаться незамеченным.
За примером далеко ходить не надо. Два года назад некто gunf прислал в форум 'Мультимедиа, графика, звук' следующий код (корневое сообщение
Никто из высказавшихся на форуме не заметил отсутствия '&'. gunf сказал, что у него "около 100 000 точек".
Было бы удобно, если бы компилятор выдавал предупреждение при передаче STL-контейнера по значению. Запретить это в будущих версиях STL нельзя, так как старый код может перестать компилироваться. Для string-а неявное копирование желательно, так как он часто бывает результатом функции (например, метод ostringstream::str).
MFC-контейнеры CArray, CList и CMap наследуют от CObject. Для CObject неявное копирование запрещено:
class CObject
{
...
// Disable the copy constructor and assignment by default so you will get
// compiler errors instead of unexpected behaviour if you pass objects
// by value or assign objects.protected:
CObject();
private:
CObject(const CObject& objectSrc); // no implementationvoid operator=(const CObject& objectSrc); // no implementation
...
};
Соответственно, оно запрещено и для всех наследников CObject, включая CArray, CList и CMap. CString неявно копируется (в MFC 4.2 дёшево).
3. Нет понятия 'NULL-итератор'. В качестве итератора, "ссылающегося в никуда", обычно используют Container.end(). Но вместо кода:
if (m_itSelectedItem != m_pServer->ItemsEnd())
{
m_pServer->ReleaseItem(m_itSelectedItem);
m_itSelectedItem = m_pServer->ItemsEnd();
}
Особенно, если такого кода много. Вариант с NULL-итератором лучше по всем показателям:
Быстрее читается.
Быстрее пишется.
Быстрее работает.
Порождает меньше машинных инструкций.
(Естественно, при условии вменяемой реализации.)
Иногда бывает так, что контейнера ещё нет, а итератор уже есть. Например, объект, содержащий контейнер, ещё не создан. Тогда не получится инициализировать итератор end-ом. Придётся оставить итератор неинициализированным. Если программист случайно использует такой итератор, то есть риск тихой порчи памяти. Если бы была возможность инициализировать итератор NULL-ом, то смерть программы была бы быстрой и безболезненной (access violation).
Теоретически, можно завести липовый статический контейнер только ради того, чтобы иметь с него end-итератор. Но. Во-первых, это криво. Во-вторых, строго говоря, нельзя сравнивать итераторы от разных контейнеров (это логическая ошибка, хотя фактически работает).
Обычно итераторы — это обёртки над указателями:
template<typename TElem, ...>
class vector
{
...
typedef TElem* iterator;
...
};
template<typename TElem, ...>
class list
{
...
struct Node
{
Node* pPrev;
Node* pNext;
TElem Elem;
};
...
class iterator
{
Node* m_pNode;
...
};
...
};
Поэтому понятие 'NULL-итератор' можно безболезненно ввести в STL. MSVC6 STL "поддерживает" NULL-итераторы.
В MFC-контейнерах CList и CMap для итерации используется тип POSITION. Это typedef указателя:
Поэтому POSITION вполне законно может быть NULL. Хотя такой вариант итераторов не type-safe, так как для всех конкретизаций CList и CMap используется один и тот же тип.
4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
Два года назад Кирпа В.А. сообщил в этот форум о своей проблеме (корневое сообщение
Выражение стало вычисляться как раньше.
Другой пример. Страуструп в книге "Язык программирования C++" (третье издание) в разделе 17.6 разрабатывает hash_map в стиле STL-контейнера. В разделе 17.6.2.2 приведён следующий код:
template<...>
void hash_map::resize(size_type s)
{
...
if (no_of_erased) {
for (size_type i = v.size() - 1; 0 <= i; i--)
if (v[i].erased) {
v.erase(&v[i]);
if (--no_of_erased == 0) break;
}
}
...
}
Если size_type = size_t (по умолчанию), то условие "0 <= i" бессмысленно, так как значение переменной беззнакового типа всегда >= 0. Как ни странно, код работает правильно, так как no_of_erased — это количество элементов vector-а v, у которых erased = true.
Здесь Страуструп стал жертвой "STL-стиля". Сам он всячески призывает программиста использовать int. Та же книга, раздел 4.4 ("Целые типы"):
Типы unsigned (без знака) идеально подходят для задач, в которых память интерпретируется как массив битов. Использование unsigned вместо int с целью заработать лишний бит для представления положительных целых почти всегда оказывается неудачным решением. Использование же объявления unsigned для гарантии того, что целое будет неотрицательным, почти никогда не сработает из-за правил неявного преобразования типов (§ В.6.1, § В.6.2.1).
Именно эти правила неявного преобразования типов "подменили" -1 на 4294967295 в программе Кирпы.
В разделе 4.10 ("Советы"):
[18] Избегайте беззнаковой арифметики; § 4.4.
[19] С подозрением относитесь к преобразованиям из signed в unsigned и из unsigned в signed; § В.6.2.6.
Какое отношение size_t имеет к array-based контейнерам (vector, string), ещё понятно: в языках C/C++ длина/индекс массива выражаются типом size_t. Какое отношение size_t имеет к node-based контейнерам (list, map), непонятно совсем. В 90-ые годы (время проектирования STL), когда ещё живы были 16-битные платформы, использование size_t было оправдано. Сейчас это источник тонких ошибок.
"Проблему size_t" можно решить несколькими способами:
Указать allocator с size_type = int.
Сделать обёртку над контейнером:
template<typename TElem>
class MyList : public list<TElem>
{
public:
int size() const { return list<TElem>::size(); }
};
Всё время оборачивать "Container.size()" приведением к int.
В MFC-контейнерах количество элементов и индекс массива выражаются типом int:
template<...>
class CArray : public CObject
{
...
int GetSize() const;
...
// overloaded operator helpers
TYPE operator[](int nIndex) const;
TYPE& operator[](int nIndex);
...
};
template<...>
class CList : public CObject
{
...
// count of elementsint GetCount() const;
...
};
template<...>
class CMap : public CObject
{
...
// number of elementsint GetCount() const;
...
};
class CString
{
...
// get data lengthint GetLength() const;
...
// return single character at zero-based index
TCHAR operator[](int nIndex) const;
...
};
Реализации operator[] проверяют (ASSERT-ами), что индекс >= 0. В преддверии Win64 int обобщили до INT_PTR.
5. Нельзя получить итератор по указателю на элемент контейнера за константное время. Например, есть такой код:
class Item
{
public:
void AddRef();
void Release();
string Name() const;
private:
friend class ItemManager;
ItemManager* m_pManager;
int m_Refs;
string m_Name;
Item(ItemManager* pManager, const string& Name);
};
class ItemManager
{
public:
Item* AddItem(const string& Name);
private:
friend class Item;
list<Item> m_Items;
void RemoveItem(Item* pItem);
};
Item* ItemManager::AddItem(const string& Name)
{
m_Items.push_back(Item(this, Name));
return &m_Items.back();
}
void ItemManager::RemoveItem(Item* pItem)
{
// получить итератор по указателю на элемент списка
list<Item>::iterator it = m_Items.begin();
while (&*it != pItem)
{
++it;
}
m_Items.erase(it);
}
Item::Item(ItemManager* pManager, const string& Name) :
m_pManager(pManager),
m_Refs(1),
m_Name(Name)
{
}
void Item::AddRef()
{
m_Refs++;
}
void Item::Release()
{
m_Refs--;
if (m_Refs == 0)
{
m_pManager->RemoveItem(this);
}
}
Желательно, чтобы код, выделенный жирным, работал за константное время. То есть чтобы в STL было что-нибудь вроде:
6. Вместо метода empty удобнее был бы метод с позитивным смыслом, например has_elems (возвращает true <=> в контейнере есть хотя бы один элемент). Можно сделать обёртку над контейнером:
template<typename TElem>
class MyList : public list<TElem>
{
public:
bool has_elems() const { return !empty(); }
};
7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне.
8. vector
8.1. Странное название у этого контейнера. В математике вектор содежит фиксированное количество элементов. Поэтому математический вектор похож на Pascal-евский массив, для которого "размер массива является частью его типа". Поначалу слово 'vector' может сбить с толку.
В MFC соответствующий контейнер называется 'CArray'.
Проблему упомянул LaptevVV здесь
8.2. Динамический "массив битов" лучше было бы оформить как отдельный класс (например, dyn_bit_array), а не как специализацию vector<bool>. Нынешнее решение нарушает обобщённость vector-а. В будущем, возможно, динамический "массив битов" выделят в отдельный класс и обобщённость vector-а будет восстановлена.
Проблему упомянули Mazay здесь
Всё это странно, так как Страуструп в книге "Дизайн и эволюция языка C++" пишет (в самом конце 8-ой главы):
Одобрен также класс динамического массива dynarray [Stal, 1993], шаблон класса bits<N> для битовых множеств фиксированного размера, класс bitstring для битовых множеств с изменяемым размером. Кроме того, комитет принял классы комплексных чисел (предшественник — первоначальный класс complex, см. раздел 3.3), обсуждается вопрос, следует ли принять класс вектора для поддержки численных расчётов и научных приложений. О наборе стандартных классов, их спецификациях и даже названиях всё ещё ведутся оживлённые споры.
Там же есть сноска:
...
Разумеется, STL содержит классы для отображений и списков и включает в качестве частных случаев вышеупомянутые классы dynarray, bits и bitstring. Кроме того, комитет одобрил классы векторов для поддержки численных и научных расчётов, приняв за основу предложение Кена Баджа из Sandia Labs.
Видимо, в ходе стандартизации, кто-то, слабо знакомый с математикой, переименовал dynarray в vector и спрятал bitstring под маской vector<bool>. Может быть, повлияла традиция. Функцию main обычно пишут так:
int main(int argc, char* argv[])
{
...
}
argv означает 'argument vector'.
9. list
9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). Стандарт рекомендует ("should"), чтобы list::size работал за константное время, но выбор оставлен на усмотрение реализации STL. Соответственно, есть "странные" реализации STL (например, SGI STL, раздел "Why is list<>::size() linear time?"), в которых size вычисляется, а не хранится. То есть реализация size-а пробегает по всему списку и таким образом узнаёт количество элементов.
В MFC CList::GetCount работает за константное время:
template<class TYPE, class ARG_TYPE>
AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
{ return m_nCount; }
9.2. Неизвестен порядок уничтожения элементов в деструкторе list-а. Специализированный менеджер памяти, работающий как stack, может требовать, чтобы блоки памяти освобождались в обратном порядке. Я проверил две реализации STL: MSVC6 STL и Rogue Wave STL 2.1.1 (поставляется вместе с BCB5). В обеих ~list уничтожает элементы в прямом порядке. То есть если я наполняю list push_back-ами, то stack-овый менеджер памяти использовать нельзя.
9.3. push_front и push_back не возвращают итератор на ново-вставленный элемент. Мелочь, а неудобно. В будущем это вполне можно исправить, старый код менять не придётся. Пока, можно сделать обёртку над list-ом:
В MFC-шном CList-е методы AddHead и AddTail возвращают итератор:
// add before head or after tail
POSITION AddHead(ARG_TYPE newElement);
POSITION AddTail(ARG_TYPE newElement);
10. string
10.1. Если программа много работает с текстом, то string (или его аналог) — ходовой тип. При этом желательно, чтобы неявное копирование string-а было дешёвым. Для этого реализация string-а может использовать разделяемый (между несколькими string-ами) буфер с подсчётом ссылок. Но string спроектирован в mutable стиле, поэтому у него есть не-const методы begin, end, rbegin, rend, operator[] и at. Если реализация string-а считает ссылки, то эти методы делают copy-on-write (даже если вы не собираетесь ничего менять) и запрещают разделяемость буфера. При этом неявное копирование string-а незаметно становится дорогой операцией (создание нового буфера и копирование туда char-ов). Чтобы случайно не запретить разделяемость буфера (если реализация string-а считает ссылки), можно сделать обёртку над string-ом в immutable стиле:
Теперь не-const методы базового класса (string) скрыты одноимёнными методами производного класса (которые вызывают соответствующие const методы string-а).
У MFC-шного CString-а operator[] возвращает не ссылку на char (как у STL-ного string-а), а копию char-а:
class CString
{
...
// return single character at zero-based index
TCHAR operator[](int nIndex) const;
// set a single character at zero-based indexvoid SetAt(int nIndex, TCHAR ch);
...
};
Если вы действительно хотите изменить содержимое CString-а, вы должны сказать это явно (метод SetAt). В MFC 4.2 CString считает ссылки, поэтому метод SetAt делает copy-on-write, но разделяемость буфера не запрещает.
10.2. Нет завершающего '\0'. Вот такой код:
string Text = "abc";
assert(Text[3] == '\0');
содержит логическую ошибку, так как '3' является ошибочным индексом для string-а с length = 3. Усердная реализация STL, проверяющая индекс, обнаружит это и сообщит об ошибке (с помощью assert-а или исключения). Если реализация STL беспечная (не проверяет индекс), то фактически код будет работать, так как '\0' в конец обычно ставят (чтобы иметь быструю реализацию метода c_str).
Иногда завершающий '\0' удобен при parsing-е. Например, нужно узнать, соответствует ли строка шаблону "Имя1::Имя2". Код в стиле языка C может быть такой:
bool IsValidMethodName_CStyle(const char pText[])
{
int p = 0;
// Имя1 не может начинаться с цифрыif (IsLetterOrUnderscore(pText[p])) p++; else return false;
while (IsLetterOrUnderscoreOrDigit(pText[p])) p++;
if (pText[p] == ':') p++; else return false;
if (pText[p] == ':') p++; else return false;
// Имя2 не может начинаться с цифрыif (IsLetterOrUnderscore(pText[p])) p++; else return false;
while (IsLetterOrUnderscoreOrDigit(pText[p])) p++;
return pText[p] == '\0';
}
Функции IsLetterOrUnderscore и IsLetterOrUnderscoreOrDigit возвращают false для '\0', поэтому завершающий '\0' служит барьером при parsing-е. При использовании string-а придётся добавить проверки индекса:
bool IsValidMethodName_STL(const string& Text)
{
int p = 0;
// Имя1 не может начинаться с цифрыif ((p < Text.length()) && IsLetterOrUnderscore(Text[p])) p++; else return false;
while ((p < Text.length()) && IsLetterOrUnderscoreOrDigit(Text[p])) p++;
if ((p < Text.length()) && (Text[p] == ':')) p++; else return false;
if ((p < Text.length()) && (Text[p] == ':')) p++; else return false;
// Имя2 не может начинаться с цифрыif ((p < Text.length()) && IsLetterOrUnderscore(Text[p])) p++; else return false;
while ((p < Text.length()) && IsLetterOrUnderscoreOrDigit(Text[p])) p++;
return p == Text.length();
}
"Лишние" проверки нудно писать, также они замедляют программу. Конечно, вместо 'IsValidMethodName_STL(Text)', можно писать 'IsValidMethodName_CStyle(Text.c_str())', но тогда усердная реализация STL не cможет проверять индекс. В будущем доступ к завершающему '\0' может быть разрешён.
К сожалению, MFC-шный CString запрещает доступ к завершающему '\0' (MFC 4.2):
_AFX_INLINE TCHAR CString::operator[](int nIndex) const
{
// same as GetAt
ASSERT(nIndex >= 0);
ASSERT(nIndex < GetData()->nDataLength);
return m_pchData[nIndex];
}
10.3. Нет прямого доступа к буферу на запись. Например, нужно получить введённый текст из edit control-а. Можно запросить текст "прямо в string":
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
Text.resize(Len);
::GetWindowText(hEditControl, &Text[0], Len + 1);
}
Фактически это работает, но стандарт не гарантирует, что string хранит char-ы последовательно в одном массиве (кстати, для vector-а такая гарантия есть (не считая vector<bool>)). Теоретически, string может хранить char-ы задом наперёд или в нескольких массивах (как deque). Даже если string хранит char-ы последовательно в одном массиве, теоретически место для завершающего '\0' может не резервироваться (а GetWindowText пишет его в буфер). У приведённого кода есть и практическая проблема: если реализация string-а считает ссылки, то не-const operator[] запрещает разделяемость буфера (между несколькими string-ами).
Можно воспользоваться методом c_str. Он предоставляет прямой доступ к буферу на чтение. Тут всё "честно": c_str возвращает указатель на массив char-ов, завершающийся '\0'. Код будет такой:
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
Text.resize(Len);
::GetWindowText(hEditControl, const_cast<char*>(Text.c_str()), Len + 1);
}
Фактически это тоже работает. Если реализация string-а считает ссылки, то, скорее всего, метод c_str не запрещает разделяемость буфера, доверчиво полагая, что вы не будете менять содержимое буфера. Но теоретически c_str-буфер может быть лишь копией последовательности char-ов, доступной через итераторы, operator[] и at. Если так, то изменение копии не затронет оригинал.
Единственный "законный" на данный момент способ — это использовать промежуточный буфер:
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
vector<char> Buf(Len + 1); // нужно место для завершающего '\0'
::GetWindowText(hEditControl, &Buf[0], Len + 1);
Text.assign(&Buf[0], Len);
}
Такое решение работает медленнее предыдущих вариантов и фрагментирует кучу (heap). Вместо универсальной кучи можно использовать специализированный менеджер памяти для временных выделений памяти. Иногда в таких случаях используют alloca, но это опасно, особенно в циклах (риск получить stack overflow).
Получается, что фактически быстрый код работает со всеми реализациями STL, но слишком обобщённый стандарт мешает жить совестливым программистам. А жить приходится бок о бок с C-style APIs (например, WinAPI). В будущем прямой доступ к буферу на запись может быть добавлен. Пока, проблему можно решить, введя дополнительный слой абстракции:
//#define GENERIC_STL_IMPL
//#define REALISTIC_STL_IMPLclass StringBuf
{
// неявное копирование запрещено
StringBuf(const StringBuf& s);
StringBuf& operator=(const StringBuf& s);
public:
StringBuf(string* pTarget, int Len);
char* Chars();
void Commit();
private:
#ifdef GENERIC_STL_IMPL
string* m_pTarget;
vector<char> m_Buf;
#endif
#ifdef REALISTIC_STL_IMPL
string* m_pTarget;
#endif
};
#ifdef GENERIC_STL_IMPL
StringBuf::StringBuf(string* pTarget, int Len)
{
assert(pTarget != NULL);
assert(pTarget->empty()); // строим string с нуля
assert(Len > 0);
m_pTarget = pTarget;
m_Buf.resize(Len + 1); // может понадобиться место для завершающего '\0'
}
char* StringBuf::Chars()
{
assert(m_pTarget != NULL); // ещё не было Commitreturn &m_Buf[0];
}
void StringBuf::Commit()
{
assert(m_pTarget != NULL); // ещё не было Commit
m_pTarget->assign(&m_Buf[0], m_Buf.size() - 1); // без завершающего '\0'
m_pTarget = NULL;
m_Buf.clear(); // досрочно освободить память
}
#endif// GENERIC_STL_IMPL#ifdef REALISTIC_STL_IMPL
StringBuf::StringBuf(string* pTarget, int Len)
{
assert(pTarget != NULL);
assert(pTarget->empty()); // строим string с нуля
assert(Len > 0);
m_pTarget = pTarget;
m_pTarget->resize(Len);
}
char* StringBuf::Chars()
{
assert(m_pTarget != NULL); // ещё не было Commitreturn const_cast<char*>(m_pTarget->c_str());
}
void StringBuf::Commit()
{
assert(m_pTarget != NULL); // ещё не было Commit
m_pTarget = NULL;
}
#endif// REALISTIC_STL_IMPL
Теперь код, достающий текст из edit control-а, будет такой:
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
StringBuf Buf(&Text, Len);
::GetWindowText(hEditControl, Buf.Chars(), Len + 1);
Buf.Commit();
}
Настройками компиляции можно выбрать "законный" или быстрый вариант, не меняя код. Знание особенностей реализации string-а изолировано в классе StringBuf.
MFC-шный CString предоставляет прямой доступ к буферу на запись:
CString Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
char* pBuf = Text.GetBufferSetLength(Len);
::GetWindowText(hEditControl, pBuf, Len + 1);
Text.ReleaseBuffer();
}
В MFC 4.2 CString считает ссылки. После прямого доступа к буферу на запись буфер может разделяться между несколькими CString-ами.
10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки).
Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. К счастью, такую функцию (точнее, семейство функций) можно сделать самому. Например:
struct ConcatString
{
const char* pChars;
int Len;
ConcatString(const string& s)
{
pChars = s.c_str();
Len = s.length();
}
// для строковых литералов
ConcatString(const char s[])
{
pChars = s;
Len = strlen(s);
}
};
string DoConcat(const ConcatString pStrings[], int NumStrings)
{
assert(NumStrings > 0);
int TotalLen = 0;
for (int i = 0; i < NumStrings; i++)
{
assert(pStrings[i].Len >= 0);
TotalLen += pStrings[i].Len;
}
string Total;
if (TotalLen != 0)
{
StringBuf Buf(&Total, TotalLen);
char* pTotIter = Buf.Chars();
for (int i = 0; i < NumStrings; i++)
{
ConcatString s = pStrings[i];
if (s.Len != 0)
{
memcpy(pTotIter, s.pChars, s.Len * sizeof(char));
pTotIter += s.Len;
}
}
Buf.Commit();
}
return Total;
}
string Concat(ConcatString s1, ConcatString s2)
{
const ConcatString Strings[] = { s1, s2 };
return DoConcat(Strings, 2);
}
string Concat(ConcatString s1, ConcatString s2, ConcatString s3)
{
const ConcatString Strings[] = { s1, s2, s3 };
return DoConcat(Strings, 3);
}
// и так далее
В функции DoConcat можно использовать класс ostringstream в качестве string builder-а.
11. У priority_queue нет метода increase_priority(element) (чтобы ускорить выталкивание элемента из очереди). Поэтому priority_queue нельзя использовать в алгоритме Дейкстры и A*. Я не знаю, как устроена структура данных 'пирамида' (heap, частично упорядоченное сортирующее дерево), так что не могу сказать, можно ли безболезненно добавить increase_priority.
КЛ>и что? что я неверно сказал?
_>Потому что одномерный array называется vector, двухмерный array называется matrix. Трёх и более специальных названий не _>имеют (насколько я знаю).
КЛ>>>тензоры
Вот это утвеждение неверно, хотя я наверно занудствую
Здравствуйте, Аноним, Вы писали:
А>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
проблемы влечет не сама беззнаковость size_t, а непоследовательность в использовании типов. и количество элементов в контейнере и индекс элемента не могут быть отрицательными — вполне логично делать их беззнаковыми. проблемы начинаются, когда в коде для них в одном месте используется знаковые типы, а в другом — беззнаковые.
зачем в вашем примере GetPos возвращает int? судя по всему только для возможности задать спец значение -1, на мой взгляд в таком случае более правильно использовать явно объявленое значение для беззнакового — как например std::string::npos.
Здравствуйте, rusted, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
А>>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
R>проблемы влечет не сама беззнаковость size_t, а непоследовательность в использовании типов. и количество элементов в контейнере и индекс элемента не могут быть отрицательными — вполне логично делать их беззнаковыми. проблемы начинаются, когда в коде для них в одном месте используется знаковые типы, а в другом — беззнаковые.
Нет. Проблемма именно в беззнаковости stl.
пример:
for(i = 0, j = vec.size()-1; i < j; i++)
{
// перебираем элементы парами, например для вычисления расстояния м-ду соседними
vec[i]; vec[i+1];
}
Со знаковыми типами вот такой код будет нормально работать, а с бесзнаковыми i,j при vec.size()==0 будут грабли.
R>зачем в вашем примере GetPos возвращает int? судя по всему только для возможности задать спец значение -1, на мой взгляд в таком случае более правильно использовать явно объявленое значение для беззнакового — как например std::string::npos.
Для того чтобы можно было писать по человечески. Если например двигаемся в произвольном направлении и с произвольным шагом, то к индексу прибавляется приращение: i+=d, а приращение вполне может быть и отрицательным.
Здравствуйте, rusted, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
А>>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
R>проблемы влечет не сама беззнаковость size_t, а непоследовательность в использовании типов. и количество элементов в контейнере и индекс элемента не могут быть отрицательными — вполне логично делать их беззнаковыми. проблемы начинаются, когда в коде для них в одном месте используется знаковые типы, а в другом — беззнаковые.
Логично использовать size_t до тех пор, пока не сядешь в лужу. С Вами, видимо, такого не случалось, а вот со мной случалось. Место жительства size_t — менеджеры памяти, лучше ему оттуда не расползаться по программе.
Создатели Java, наученные горьким опытом C++, вообще практически отказались от беззнаковых типов. uint32 в Java нет. Хотя это слишком радикальное решение: лечение головной боли путём отсечения головы. Но менеджеры памяти на Java не пишут, поэтому там это нормально.
R>зачем в вашем примере GetPos возвращает int? судя по всему только для возможности задать спец значение -1, на мой взгляд в таком случае более правильно использовать явно объявленое значение для беззнакового — как например std::string::npos.
Спросите у Кирпы. Иногда использование барьерных значений (как -1 здесь) позволяет не писать нудных граничных проверок.
Kluev wrote:
> for(i = 0, j = vec.size()-1; i < j; i++)
> Со знаковыми типами вот такой код будет нормально работать, а с > бесзнаковыми i,j при vec.size()==0 будут грабли.
А зачем такой ужас писать? Чем банальный
for(size_t i = 0; i + 1 < vec.size(); i++)
не устраивает?
> R>зачем в вашем примере GetPos возвращает int? судя по всему только для > возможности задать спец значение -1, на мой взгляд в таком случае более > правильно использовать явно объявленое значение для беззнакового — как > например std::string::npos. > > Для того чтобы можно было писать по человечески. Если например двигаемся > в произвольном направлении и с произвольным шагом, то к индексу
Для этого есть iterator.
> прибавляется приращение: i+=d, а приращение вполне может быть и > отрицательным.
Для этого есть difference_type.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Аноним, Вы писали:
А>1. Все STL-контейнеры требуют копируемость элементов. Но часто объекты в программе обладают идентичностью. Неявное копирование для них бессмысленно, а потому запрещено. Чтобы хранить такие объекты в STL-контейнере, их обычно создают динамически (new), а в контейнер помещают указатели (обычные или умные, как boost::shared_ptr). Но было бы лучше (по скорости работы программы и по расходу памяти) избежать такой косвенности. В будущем это вполне возможно, если node-based контейнеры (list, map) научатся инициализировать элементы значением произвольного типа (а не только 'const value_type&', как сейчас).
Наверное, было бы полезно, если сделать как следует (в частности, обеспечить type safety, отсутствие неявных преобразований). В C++09 проблема будет решена с помощью rvalue references.
А>2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция дорога. Например, нужно вывести список строк на консоль: А>Этот код работает нормально. Но если программист забудет '&' после 'const list<string>', то список будет передаваться уже не по ссылке, а по значению. При этом программа будет компилироваться без предупреждений и правильно работать. Лишнее копирование списка может остаться незамеченным.
Ориентируясь на забывчивых программеров, каши не сваришь. Хотя что-то в идее есть... Как только быть с функциями, возвращающими контейнер по значению?
А>3. Нет понятия 'NULL-итератор'.
Здесь не согласен.
typedef std::vector<X> Cont;
Cont cont;
Cont::const_iterator i = cont.end(); // decltype(i) = X*? Вполне возможно... или уже нет?
assert(i == std::null_iter);
--i; // и как?
++i; // и как?
assert(i == std::null_iter);
Другое дело, что многие итераторы имеют универсальным конечным итератором значение, создаваемое дефолтным конструктором (std::istream_iterator, наример). Лечится доработкой std::tr2::iterator_range.
А>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
Кривое использование вроде cont.size() — 1 всегда влечет проблемы. А если бы это были итераторы? boost::prev(cont.end())? Хотя здесь тоже сложно сказать однозначно. Если вставить cont.size() в какую-нибудь математическую формулу, можно чудеса получить... и я получал, когда делал что-то вроде кольцевого буфера:
int index = getIndex();
X& ref = vec[index % vec.size()]; // oops!
А>5. Нельзя получить итератор по указателю на элемент контейнера за константное время.
Я бы посмотрел на реализацию сего для unordered_map Без грязных хаков не обойтись, ты и сам привел примеры. И для чего это? Кому надо, выдаст наружу итераторы (typedef Cont::iterator ObjId; ObjId getSomeObject() {})
А>6. Вместо метода empty удобнее был бы метод с позитивным смыслом, например has_elems (возвращает true <=> в контейнере есть хотя бы один элемент).
ага
А>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне.
Ну, это, если и проблема, то не STL, а языка.
А>8. vector А>8.1. Странное название у этого контейнера. В математике вектор содежит фиксированное количество элементов. Поэтому математический вектор похож на Pascal-евский массив, для которого "размер массива является частью его типа". Поначалу слово 'vector' может сбить с толку.
если еще учесть std::tr1::array = boost::array, то вообще весело станет
Это не так важно, все привыкли уже.
А>8.2. Динамический "массив битов" лучше было бы оформить как отдельный класс (например, dyn_bit_array), а не как специализацию vector<bool>. Нынешнее решение нарушает обобщённость vector-а. В будущем, возможно, динамический "массив битов" выделят в отдельный класс и обобщённость vector-а будет восстановлена. А>Проблему упомянули Mazay здесь
.
...и Саттер, и Майерс, и кто только не ругал бедный std::vector<bool>...
А>Может быть, повлияла традиция. Функцию main обычно пишут так: А>argv означает 'argument vector'.
я всегда думал, что 'argument values'
А>9. list А>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). Стандарт рекомендует ("should"), чтобы list::size работал за константное время, но выбор оставлен на усмотрение реализации STL. Соответственно, есть "странные" реализации STL (например, SGI STL, раздел "Why is list<>::size() linear time?"), в которых size вычисляется, а не хранится. То есть реализация size-а пробегает по всему списку и таким образом узнаёт количество элементов. А>О проблеме писали здесь
.
в чем проблема-то? Ты б хоть сформулировал ее. В (чрезмерной) мягкости стандарта?
А>9.2. Неизвестен порядок уничтожения элементов в деструкторе list-а. Специализированный менеджер памяти, работающий как stack, может требовать, чтобы блоки памяти освобождались в обратном порядке. Я проверил две реализации STL: MSVC6 STL и Rogue Wave STL 2.1.1 (поставляется вместе с BCB5). В обеих ~list уничтожает элементы в прямом порядке. То есть если я наполняю list push_back-ами, то stack-овый менеджер памяти использовать нельзя.
ну может быть... сделать вроде легко.
А>9.3. push_front и push_back не возвращают итератор на ново-вставленный элемент. Мелочь, а неудобно. В будущем это вполне можно исправить, старый код менять не придётся.
можно...
А>10. string
Эх, не ругал только ленивый... Хуже всего, что есть за что
А>10.1. можно сделать обёртку над string-ом в immutable стиле:
можно
А>10.2. Нет завершающего '\0'. Вот такой код:
'\0' нужен только для legacy кода. Для нового есть end().
А>Иногда завершающий '\0' удобен при parsing-е. Например, нужно узнать, соответствует ли строка шаблону "Имя1::Имя2". Код в стиле языка C может быть такой: А>Функции IsLetterOrUnderscore и IsLetterOrUnderscoreOrDigit возвращают false для '\0', поэтому завершающий '\0' служит барьером при parsing-е. При использовании string-а придётся добавить проверки индекса: А>
bool IsValidMethodName_STL(const string& Text)
{
int p = 0;
... ++p ... p++ ... if(2 * 2 == 5) p += 14; ...
return p == Text.length();
}
Разве это STL style?
template <class II>
bool IsValidMethodName_RealStlStyle(II first, II last)
{
II p = first;
... ++p ... p++ ... if(2 * 2 == 5) p += 14; ...
return p == last;
}
А>10.3. Нет прямого доступа к буферу на запись. Например, нужно получить введённый текст из edit control-а. Можно запросить текст "прямо в string":
Опять же, для legacy кода?
А>10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки). А>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. К счастью, такую функцию (точнее, семейство функций) можно сделать самому. Например:
Здесь более в духе STL было бы что-то вроде join_iterator. Тоже можно самому написать.
Roman Odaisky wrote:
> А>2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция > дорога. Например, нужно вывести список строк на консоль: > А>Этот код работает нормально. Но если программист забудет '&' после > 'const list<string>', то список будет передаваться уже не по ссылке, а > по значению. При этом программа будет компилироваться без предупреждений > и правильно работать. Лишнее копирование списка может остаться незамеченным. > Ориентируясь на забывчивых программеров, каши не сваришь. Хотя что-то в > идее есть... Как только быть с функциями, возвращающими контейнер по > значению?
Да нет, здесь всё ок. Тем более если осталось незамеченным — ради бога, пусть копируется жалко что-ли? Вдруг там список
обычно из 3 элементов и вызывается это раз в пятилетку? А если это источник тормозов — профайлер такие вещи показывает
на раз.
> А>6. Вместо метода empty удобнее был бы метод с позитивным смыслом, > например has_elems (возвращает true <=> в контейнере есть хотя бы один > элемент). > ага
Фиолетово. Да и к тому же вариант с isEmpty или подобным — наиболее распространён.
"if(cont.size())", "если обладает размером"
> А>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на > практике не сталкивался. Теоретически, может возникнуть при неудачном > дизайне. > Ну, это, если и проблема, то не STL, а языка.
Я бы тоже не отказался, но не в таком виде, а в виде:
Cont cont = makeContainer();
Cont::const_iterator iter = chooseSomeElement(cont); // chooseSomeElement берёт на вход const Cont&, что логично, и
может вернуть только const_iterator
Cont::iterator nonconst_iter = cont.make_nonconst(iter);// Вот такое хочу!
cont.erase(nonconst_iter);// иначе, например, такое не сделать. :(
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Аноним, Вы писали:
А>3. Нет понятия 'NULL-итератор'. В качестве итератора, "ссылающегося в никуда", обычно используют Container.end(). Но вместо кода: А>
А>Особенно, если такого кода много. Вариант с NULL-итератором лучше по всем показателям:
А>Быстрее читается.
Как-то не было проблем с чтением.
А>Быстрее пишется.
В современных IDE разницы практически нет.
А>Быстрее работает. А>Порождает меньше машинных инструкций.
Не факт, компилятор может встроить тело end () в место вызова.
А>Иногда бывает так, что контейнера ещё нет, а итератор уже есть. Например, объект, содержащий контейнер, ещё не создан. Тогда не получится инициализировать итератор end-ом. Придётся оставить итератор неинициализированным. Если программист случайно использует такой итератор, то есть риск тихой порчи памяти. Если бы была возможность инициализировать итератор NULL-ом, то смерть программы была бы быстрой и безболезненной (access violation). А>Теоретически, можно завести липовый статический контейнер только ради того, чтобы иметь с него end-итератор. Но. Во-первых, это криво. Во-вторых, строго говоря, нельзя сравнивать итераторы от разных контейнеров (это логическая ошибка, хотя фактически работает). А>Обычно итераторы — это обёртки над указателями: А>
А>Поэтому понятие 'NULL-итератор' можно безболезненно ввести в STL. MSVC6 STL "поддерживает" NULL-итераторы.
Итераторы могут быть классами, а не простыми указателями (как в STLPort в отладочном билде),
в этом случае такой поход работать не будет.
А>В MFC-контейнерах CList и CMap для итерации используется тип POSITION. Это typedef указателя:
MFC — это совсем другая история, там нет обобщенных алгоритмов.
А>5. Нельзя получить итератор по указателю на элемент контейнера за константное время.
<код поскипан> А>Желательно, чтобы код, выделенный жирным, работал за константное время.
А кто сказал, что это возможно для любых итераторов и любых контейнеров?
А>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне.
Я тоже с такой проблемой не сталкивался.
А>8. vector А>8.1. Странное название у этого контейнера.
Теперь его уже поздно менять .
А>9. list А>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). Стандарт рекомендует ("should"), чтобы list::size работал за константное время, но выбор оставлен на усмотрение реализации STL. Соответственно, есть "странные" реализации STL (например, SGI STL, раздел "Why is list<>::size() linear time?"), в которых size вычисляется, а не хранится. То есть реализация size-а пробегает по всему списку и таким образом узнаёт количество элементов. А>В MFC CList::GetCount работает за константное время: А>
А>
А>template<class TYPE, class ARG_TYPE>
А>AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
А> { return m_nCount; }
А>
.
То, что в одной из реализаций STL list::size () имеет линейную сложность еще ни очем не говорит.
Да и есть ли в CList аналог list::splice ()?
А>9.2. Неизвестен порядок уничтожения элементов в деструкторе list-а. Специализированный менеджер памяти, работающий как stack, может требовать, чтобы блоки памяти освобождались в обратном порядке. Я проверил две реализации STL: MSVC6 STL и Rogue Wave STL 2.1.1 (поставляется вместе с BCB5). В обеих ~list уничтожает элементы в прямом порядке. То есть если я наполняю list push_back-ами, то stack-овый менеджер памяти использовать нельзя.
А когда это нужно?
На мой вгляд, закладываться на особенности внутренней реализации контейнера не есть правильно.
А>9.3. push_front и push_back не возвращают итератор на ново-вставленный элемент. Мелочь, а неудобно. В будущем это вполне можно исправить, старый код менять не придётся. Пока, можно сделать обёртку над list-ом: А>
Гм, а почему нельзя просто использовать list::front () и list::back ()?
Мне кажется, что операции получения итераторов на элементы и вставка разделены не
просто так, а для того, чтобы можно было гарантировать предсказуемое состояние
программы в случае, если итератор является классом и при его копировании
может вылететь исключение:
class A { int n; };
list<A> list_of_A;
list<A>::iterator it = list_of_A.push_back (A ()); // если здесь вылетело исключение о нехватки памяти, как
// определить произошло это при вставке элемента в контейнер
// или при копировании итератора? И в каком состоянии
// теперь находится list_of_A, был ли в него добавлен
// элемент?
А>В MFC-шном CList-е методы AddHead и AddTail возвращают итератор:
В MFC железно зашито, что POSITION является указателем.
А>10. string А>10.1. Если программа много работает с текстом, то string (или его аналог) — ходовой тип. При этом желательно, чтобы неявное копирование string-а было дешёвым. Для этого реализация string-а может использовать разделяемый (между несколькими string-ами) буфер с подсчётом ссылок.
Сейчас , на сколько я знаю, отходят от использования COW при реализации std::string из-за проблем с многопоточностью,
к тому же это только одна из возможных реализаций. Все-таки как-то странно подгонять интерфейс под реализацию.
С другой стороны, может было бы лучше как в Java реализовать отдельно классы для неизменяемых строк и строк с возможностью изменения.
А>10.2. Нет завершающего '\0'. Вот такой код: А>
А>string Text = "abc";
А>assert(Text[3] == '\0');
А>
А>содержит логическую ошибку, так как '3' является ошибочным индексом для string-а с length = 3. Усердная реализация STL, проверяющая индекс, обнаружит это и сообщит об ошибке (с помощью assert-а или исключения). Если реализация STL беспечная (не проверяет индекс), то фактически код будет работать, так как '\0' в конец обычно ставят (чтобы иметь быструю реализацию метода c_str).
Используйте правильную STL
Вообще-то не понял, в чем проблема. Насколько я знаю, в string обычно хранится именно NULL terminating строка.
Где это не так?
А>Иногда завершающий '\0' удобен при parsing-е.
Парсинг это частная задача и подгонять std::string под вашу конкретную его реализацию
несколько станно. Целесообразнее, IMHO, парсинг проводить с помощью алгоритмов, регулярных выражений или конечных автоматов.
А>"Лишние" проверки нудно писать, также они замедляют программу. Конечно, вместо 'IsValidMethodName_STL(Text)', можно писать 'IsValidMethodName_CStyle(Text.c_str())', но тогда усердная реализация STL не cможет проверять индекс. В будущем доступ к завершающему '\0' может быть разрешён.
Ага, что бы пользователь класса сам мог этот нуль затереть и получить AV или SEGFAULT при вызове std::string::find например
А>10.3. Нет прямого доступа к буферу на запись.
Это позволяет string-у самому управляться со своими данными, что предотвращает проблемы некорректного с ними отношения со стороны
пользователя.
Например, нужно получить введённый текст из edit control-а. Можно запросить текст "прямо в string": А>
Ну да, а если пользователь забыл вызвать resize () или указал недостаточный размер? Кроме того, как тогда быть
с выделенным:
А>Фактически это работает, но стандарт не гарантирует, что string хранит char-ы последовательно в одном массиве (кстати, для vector-а такая гарантия есть (не считая vector<bool>)). Теоретически, string может хранить char-ы задом наперёд или в нескольких массивах (как deque).
А>Получается, что фактически быстрый код работает со всеми реализациями STL, но слишком обобщённый стандарт мешает жить совестливым программистам. А жить приходится бок о бок с C-style APIs (например, WinAPI). В будущем прямой доступ к буферу на запись может быть добавлен. Пока, проблему можно решить, введя дополнительный слой абстракции:
<код поскипан> А>Настройками компиляции можно выбрать "законный" или быстрый вариант, не меняя код.
А если в одном месте кода нужно быстро, а в другом месте безопасно?
Лучше использовать отдельный класс для манипуляций со строками.
А>10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки). А>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом.
То же самое, для критичного по производительности кода лучше использовать специализированный класс для манипуляций со строками. А>В функции DoConcat можно использовать класс ostringstream в качестве string builder-а.
А вот это точно не стоит использовать в критичном по времени коде.
А>11. У priority_queue нет метода increase_priority(element) (чтобы ускорить выталкивание элемента из очереди). Поэтому priority_queue нельзя использовать в алгоритме Дейкстры и A*. Я не знаю, как устроена структура данных 'пирамида' (heap, частично упорядоченное сортирующее дерево), так что не могу сказать, можно ли безболезненно добавить increase_priority.
Скорее всего, increase_priority придется сначала находить нужный элемент, удалять его и вставлять повторно с новым приоритетом.
А>Пётр Седов
Здравствуйте, Roman Odaisky, Вы писали:
А>>2. Все STL-контейнеры неявно копируются. RO>Ориентируясь на забывчивых программеров, каши не сваришь. Хотя что-то в идее есть... Как только быть с функциями, возвращающими контейнер по значению?
Я иногда бываю "забывчивый". Так что для меня это проблема.
Если результат функции — контейнер, не string, то лучше его создать динамически (new), а вызывающему коду вернуть указатель (обычный или умный) на контейнер.
Я за то, чтобы неявные операции были дёшевы, а потенциально дорогие операции (например, копирование контейнера, не string) были явными. Так как string часто бывает результатом функции, то для него желательно дешёвое копирование.
А>>3. Нет понятия 'NULL-итератор'. RO>Здесь не согласен. RO>
RO>typedef std::vector<X> Cont;
RO>Cont cont;
RO>Cont::const_iterator i = cont.end(); // decltype(i) = X*? Вполне возможно... или уже нет?
RO>assert(i == std::null_iter);
RO>--i; // и как?
RO>++i; // и как?
RO>assert(i == std::null_iter);
RO>
Я имел в виду, чтобы NULL-итератор был не вместо end-итератора, а в дополнение к нему:
end-итератор используется в паре с begin-итератором, чтобы указать алгоритму входную последовательность. Алгоритм работает с полу-интервалом [begin, end).
NULL-итератор используется, чтобы ссылаться "в никуда" (как и NULL-указатель). Его нельзя разыменовывать (*, ->), нельзя продвигать на предыдущий/следующий элемент (--/++); можно только сравнивать с другими итераторами (==, !=).
То, что для пустого vector-а эти два итератора равны, проблем создавать не должно.
Можно использовать boost::optional<iterator>, но лучше не усложнять.
RO>Другое дело, что многие итераторы имеют универсальным конечным итератором значение, создаваемое дефолтным конструктором (std::istream_iterator, наример). Лечится доработкой std::tr2::iterator_range.
Я имел в виду именно итераторы STL-контейнеров.
А>>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы. RO>Кривое использование вроде cont.size() — 1 всегда влечет проблемы. А если бы это были итераторы? boost::prev(cont.end())? Хотя здесь тоже сложно сказать однозначно. Если вставить cont.size() в какую-нибудь математическую формулу, можно чудеса получить... и я получал, когда делал что-то вроде кольцевого буфера: RO>
Я предупредил начинающих, что под size_t грабли лежат. А уж использовать его или нет — пускай сами решают.
А>>5. Нельзя получить итератор по указателю на элемент контейнера за константное время. RO>Я бы посмотрел на реализацию сего для unordered_map Без грязных хаков не обойтись, ты и сам привел примеры. И для чего это? Кому надо, выдаст наружу итераторы (typedef Cont::iterator ObjId; ObjId getSomeObject() {})
Если unordered_map — это node-based контейнер, то его iterator_from_pointer будет такой же, как у list-а.
Можно сделать классы ItemManager и Item так, как Вы сказали:
class Item
{
public:
string Name() const;
private:
friend class ItemManager;
int m_Refs;
string m_Name;
explicit Item(const string& Name);
};
class ItemManager
{
public:
typedef list<Item>::iterator ItemHandle; // Вы назвали 'ObjId'
ItemHandle AddItem(const string& Name); // Вы назвали 'getSomeObject'void AddRefItem(ItemHandle hItem);
void ReleaseItem(ItemHandle hItem);
private:
list<Item> m_Items;
};
ItemManager::ItemHandle ItemManager::AddItem(const string& Name)
{
// push_back не возвращает итераторreturn m_Items.insert(m_Items.end(), Item(Name));
}
void ItemManager::AddRefItem(ItemHandle hItem)
{
hItem->m_Refs++;
}
void ItemManager::ReleaseItem(ItemHandle hItem)
{
hItem->m_Refs--;
if (hItem->m_Refs == 0)
{
m_Items.erase(hItem);
}
}
Item::Item(const string& Name) :
m_Refs(1),
m_Name(Name)
{
}
Но. Во-первых, неудобно всюду таскать два значения (ItemManager* и ItemManager::ItemHandle) вместо одного (Item*). Во-вторых, именами 'AddRef' и 'Release' я намекал на технологию COM. Там не получится "выдать наружу итератор". Выдавать наружу придётся указатель на интерфейс (Item*). В этом случае STL-ный list без iterator_from_pointer проигрывает ручному списку в стиле языка C:
А>>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне. RO>Ну, это, если и проблема, то не STL, а языка.
Я неточно выразился. Я не про "перегрузку const_cast". Программист может явно убрать константность с указателя (с помощью const_cast). Итератор — это обобщение указателя, поэтому также может понадобиться снять константность с итератора. Не обязательно const_cast-ом, можно методом:
Существующий вариант снятия константности:
const_iterator сit
distance(const begin, сit) => индекс ix
advance(begin, ix) => iterator it
смотрится криво.
А>>8. vector А>>8.1. Странное название у этого контейнера. RO>если еще учесть std::tr1::array = boost::array, то вообще весело станет RO>Это не так важно, все привыкли уже.
+ valarray
Да, все привыкли к ещё одной программистской традиции, идущей вразрез с математикой. Одно из самых сложных действий в программировании — придумать хорошее имя для сущности. 'vector' — неудачное имя для динамического массива. Но это разговор для другого форума.
А>>8.2. vector<bool> А>>Проблему упомянули Mazay здесь
. RO>...и Саттер, и Майерс, и кто только не ругал бедный std::vector<bool>...
vector<bool> — это странно. Авторы STL провозглашают обобщённость, но сами же нарушают обобщённость vector-а.
А>>Может быть, повлияла традиция. Функцию main обычно пишут так: А>>argv означает 'argument vector'. RO>я всегда думал, что 'argument values'
В Google я запросил поиск по слову 'argv'. В первой же строчке увидел:
The name of the variable argv stands for "argument vector".
А>>9. list А>>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). Стандарт рекомендует ("should"), чтобы list::size работал за константное время, но выбор оставлен на усмотрение реализации STL. Соответственно, есть "странные" реализации STL (например, SGI STL, раздел "Why is list<>::size() linear time?"), в которых size вычисляется, а не хранится. То есть реализация size-а пробегает по всему списку и таким образом узнаёт количество элементов. А>>О проблеме писали здесь
. RO>в чем проблема-то? Ты б хоть сформулировал ее. В (чрезмерной) мягкости стандарта?
Во многих реализациях STL list::size очень дёшев, но в некоторых ("странных") реализациях STL list::size дорог. Если беспечно использовать дешёвый list::size, то при переходе на "странную" реализацию STL программа замедлится.
А>>9.2. Неизвестен порядок уничтожения элементов в деструкторе list-а. Специализированный менеджер памяти, работающий как stack, может требовать, чтобы блоки памяти освобождались в обратном порядке. Я проверил две реализации STL: MSVC6 STL и Rogue Wave STL 2.1.1 (поставляется вместе с BCB5). В обеих ~list уничтожает элементы в прямом порядке. То есть если я наполняю list push_back-ами, то stack-овый менеджер памяти использовать нельзя. RO>ну может быть... сделать вроде легко.
Сделать что?
А>>10.1. можно сделать обёртку над string-ом в immutable стиле: RO>можно
Этот пункт скомканный получился. Писал-то я не про обёртку, а про проблему. На примере будет яснее. Есть код, использующий MSVC6 STL (там string считает ссылки):
Невинно выглядящее условие в if-е делает две "вредные" вещи:
1. copy-on-write, хотя я не меняю содержимое CommandLineParam-а. В данном случае CommandLineParam — единственный владелец буфера, поэтому ничего не происходит.
2. Запрещает разделяемость буфера между несколькими string-ами. Это плохо, так как копирование CommandLineParam-а становится дорогим.
В MFC 4.2 CString тоже считает ссылки, но такой проблемы нет:
потому что CString::operator[] возвращает копию char-а (а не ссылку на char, как string::operator[]) и не запрещает разделяемость буфера.
Другой пример. Теперь есть код, использующий string::operator[] для изменения текста:
В данном случае copy-on-write уместен (потому что я действительно меняю содержимое FilePath), но string::operator[] по-прежнему запрещает разделяемость буфера. CString::SetAt тоже делает copy-on-write, но не запрещает разделяемость буфера:
А>>10.2. Нет завершающего '\0'. RO>'\0' нужен только для legacy кода. Для нового есть end().
Я имел в виду, что иногда барьер (завершающий '\0') позволяет не писать нудные граничные проверки ('p < Text.length()'). Раз уж все реализации string-а ставят '\0' в конец (для быстрого c_str), то, вероятно, стоит разрешить доступ к завершающему '\0' официально. Это может быть удобно и для нового кода.
А>>Иногда завершающий '\0' удобен при parsing-е. Например, нужно узнать, соответствует ли строка шаблону "Имя1::Имя2". Код в стиле языка C может быть такой: А>>Функции IsLetterOrUnderscore и IsLetterOrUnderscoreOrDigit возвращают false для '\0', поэтому завершающий '\0' служит барьером при parsing-е. При использовании string-а придётся добавить проверки индекса: А>>
RO>bool IsValidMethodName_STL(const string& Text)
RO>{
RO> int p = 0;
RO> ... ++p ... p++ ... if(2 * 2 == 5) p += 14; ...
RO> return p == Text.length();
RO>}
RO>
RO>Разве это STL style? RO>
RO>template <class II>
RO>bool IsValidMethodName_RealStlStyle(II first, II last)
RO>{
RO> II p = first;
RO> ... ++p ... p++ ... if(2 * 2 == 5) p += 14; ...
RO> return p == last;
RO>}
RO>
Я не говорил, что это STL-style. Суффикс '_STL' (не '_STLStyle') означает, что функция работает с STL-ным string-ом.
А>>10.3. Нет прямого доступа к буферу на запись. RO>Опять же, для legacy кода?
Например, для получения текста от WinAPI, минуя промежуточный буфер. Но в основном текст идёт в обратном направлении: из программы в WinAPI. Тут c_str справляется хорошо.
А>>10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки). А>>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. К счастью, такую функцию (точнее, семейство функций) можно сделать самому. Например: RO>Здесь более в духе STL было бы что-то вроде join_iterator. Тоже можно самому написать.
Итератор нужен для доступа к последовательности. Вы какую последовательность имели в виду? Я имел в виду, что вместо:
DirPath + "\\" + FileName
было бы оптимальнее писать:
Concat(DirPath, "\\", FileName)
Насколько я знаю, компилятор C# делает такую замену автоматически.
Пётр Седов wrote:
> То, что для пустого vector-а эти два итератора равны, проблем создавать > не должно. > Можно использовать boost::optional<iterator>, но лучше не усложнять.
Не понял, а чем std::vector<X>::const_iterator() не устраивает?
> Я предупредил начинающих, что под size_t грабли лежат. А уж использовать > его или нет — пускай сами решают.
Тут проблема не в STL, а знании начинающими арифметики и понимании операции вычитания. Всегда можно a == b — 1
преобразовать в a + 1 == b
> А>>5. Нельзя получить итератор по указателю на элемент контейнера за > константное время.
> проигрывает ручному списку в стиле языка C:
Это называется intrusive containers
> это обобщение указателя, поэтому также может понадобиться снять > константность с итератора. Не обязательно const_cast-ом, можно методом:
+
> А>>8. vector > А>>8.1. Странное название у этого контейнера. > RO>если еще учесть std::tr1::array = boost::array, то вообще весело станет > RO>Это не так важно, все привыкли уже. > + valarray > Да, все привыкли к ещё одной программистской традиции, идущей вразрез с > математикой. Одно из самых сложных действий в программировании — > придумать хорошее имя для сущности. 'vector' — неудачное имя для > динамического массива. Но это разговор для другого форума.
Я уже объяснял. Array — общее название массивов. Одномерный array называется vector (вспомни алгебру — там есть даже два
понятия — вектор-столбец и вектор-строка), двумерный — matrix. В STL vector есть одномерный array, так что наоборот, всё
очень точно.
> DirPath + "\\" + FileName > > > было бы оптимальнее писать: > > Concat(DirPath, "\\", FileName)
Но в С++ нет функций с переменным числом аргументов (ellipsis не считается). И ради одной только операции конкатенации
вводить такую штуку?..
> Насколько я знаю, компилятор C# делает такую замену автоматически.
Хаки? Или как там это работает?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Alex_Avr wrote:
> Гм, а почему нельзя просто использовать list::front () и list::back ()? > Мне кажется, что операции получения итераторов на элементы и вставка > разделены не > просто так, а для того, чтобы можно было гарантировать предсказуемое > состояние > программы в случае, если итератор является классом и при его копировании > может вылететь исключение: > > > class A { int n; }; > > list<A> list_of_A; > list<A>::iterator it = list_of_A.push_back (A ()); // если здесь вылетело исключение о нехватки памяти, как > // определить произошло это при вставке элемента в контейнер > // или при копировании итератора? И в каком состоянии > // теперь находится list_of_A, был ли в него добавлен > // элемент?
А как же std::map::insert, возвращающий аж pair? Как-то непоследовательно получается... Уж проще оператор копирования
итератора no-throw сделать, тем более это возможно (по крайней мере для всех стандартных контейнеров).
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Evgeniy13, Вы писали:
E>у нас в проекте во многих местах есть проверки, что malloc вернет ноль — это лишь откладывает ошибку на некоторое (не такое уж и большое время), а если разрабатывать суперстабильную систему, то все равно нужно как-то обрабатывать подобные исключительные ситуации (тогда какая разница: поймать исключение или проверить результат функции?)... а может вообще vector, например, должен _молча_ выделить столько, сколько сможет и все?!
Насчет разницы.
Возвращаемое значение легче увидеть в коде, особенно если делать последовательно все функции с возвратом ошибок. В С это делается автоматически, так как возвращаемое значение плюс возможно что-то вроде errno, это практически единственный механизм обработки ошибок, не считая экзотического setjmp, который я видел только в одном Open Source проекте (http://www.lua.org/pil/24.3.html).
Игнорирование возвращаемого значения легко заметить с помощью ключа -Wall и т.п.
При использовании исключений это менее заметно, отчасти из-за отсутсвия диагностики. А замечать это нужно, так как выбрасывание исключений (впрочем, как и преждевременный возврат из функции по ошибке), может легко нарушить инварианты.
Например, при использовании возвращаемого значения часто забывают освободить ранее выделенный в этой функции ресурс. С++ эту проблему решает с помощью RAII. Но к сожалению, она не все случаи охватывает. Типичный пример, это последовательное добавление элемента в различные контейнеры внутри одного объекта. Кто-нибудь делает откат, вызывая pop/pop_front/pop_back после выбрасывания исключений? Некоторые используют ScopeGuard и это хорошо, но он тоже не все случаи покрывает.
[]
А>>>10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки). А>>>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. К счастью, такую функцию (точнее, семейство функций) можно сделать самому. Например: RO>>Здесь более в духе STL было бы что-то вроде join_iterator. Тоже можно самому написать. ПС>Итератор нужен для доступа к последовательности. Вы какую последовательность имели в виду? Я имел в виду, что вместо: ПС>
ПС>DirPath + "\\" + FileName
ПС>
ПС>было бы оптимальнее писать: ПС>
ПС>Concat(DirPath, "\\", FileName)
ПС>
чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло.
ПС>Насколько я знаю, компилятор C# делает такую замену автоматически.
Здравствуйте, kan, Вы писали:
kan>Kluev wrote:
>> for(i = 0, j = vec.size()-1; i < j; i++)
>> Со знаковыми типами вот такой код будет нормально работать, а с >> бесзнаковыми i,j при vec.size()==0 будут грабли. kan>А зачем такой ужас писать? Чем банальный
kan>for(size_t i = 0; i + 1 < vec.size(); i++) kan>не устраивает?
Такая форма записи неестественная и не соотвествует ходу мышления.
>> R>зачем в вашем примере GetPos возвращает int? судя по всему только для >> возможности задать спец значение -1, на мой взгляд в таком случае более >> правильно использовать явно объявленое значение для беззнакового — как >> например std::string::npos. >> >> Для того чтобы можно было писать по человечески. Если например двигаемся >> в произвольном направлении и с произвольным шагом, то к индексу kan>Для этого есть iterator.
С итераторами неудобно работать.
1) они становятся невалидными после ресайза
2) программу неудобно отлаживать, т.к. итератор ничего не говорит ни о номере итерации, ни о индексе элемента в массиве.
Kluev wrote:
>> > for(i = 0, j = vec.size()-1; i < j; i++) > >> > Со знаковыми типами вот такой код будет нормально работать, а с >> > бесзнаковыми i,j при vec.size()==0 будут грабли. > kan>А зачем такой ужас писать? Чем банальный > > kan>for(size_t i = 0; i + 1 < vec.size(); i++) > kan>не устраивает? > Такая форма записи неестественная и не соотвествует ходу мышления.
Мышление переделай. Но запись абсолютно естественна — проверить, что выражение "i+1", которое мы используем как индекс,
не выходит за пределы размера вектора. А что означает "i < vec.size() — 1", особенно в случае нулевого размера?
Ещё прошу заметить, что понятие отрицательного индекса — вообще противоестественна, а поэтому может трактоваться по
разному. Например, в перле, обратиться по индексу "-2" — валидная операция, означает взять второй элемент с конца.
>> > R>зачем в вашем примере GetPos возвращает int? судя по всему только для >> > возможности задать спец значение -1, на мой взгляд в таком случае более >> > правильно использовать явно объявленое значение для беззнакового — как >> > например std::string::npos. >> > >> > Для того чтобы можно было писать по человечески. Если например двигаемся >> > в произвольном направлении и с произвольным шагом, то к индексу > kan>Для этого есть iterator. > С итераторами неудобно работать. > 1) они становятся невалидными после ресайза > 2) программу неудобно отлаживать, т.к. итератор ничего не говорит ни о > номере итерации, ни о индексе элемента в массиве.
Индекс для вектора всегда "iter — vec.begin()"
В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan, Вы писали:
>> DirPath + "\\" + FileName >> >> было бы оптимальнее писать: >> >> Concat(DirPath, "\\", FileName) kan>Но в С++ нет функций с переменным числом аргументов (ellipsis не считается).
Здравствуйте, kan_izh, Вы писали:
_>Шахтер wrote:
>> Ш>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. >> Это огромный минус. >> >> _>это элементарно обходится: используй контейнеры на SmartPtr, а сам >> указатель может быть и некопирабельным. >> >> >> И аллокировать каждый объект в динамической памяти? >> Нет, спасибо. _>А как ты тогда себе представляешь динамический массив без возможности скопировать элемент?
Я его не представляю. Я его использую.
_>Вроде только если будут move constructor... это обещают в следующей версии языка... но...
Да не нужна новая версия языка для этого. Всё прекрасно можно сделать на старой.
Здравствуйте, kan, Вы писали:
kan>Roman Odaisky wrote: >> А>2. Все STL-контейнеры неявно копируются. >> Ориентируясь на забывчивых программеров, каши не сваришь. Хотя что-то в >> идее есть... Как только быть с функциями, возвращающими контейнер по >> значению? kan>Да нет, здесь всё ок. Тем более если осталось незамеченным — ради бога, пусть копируется жалко что-ли? Вдруг там список kan>обычно из 3 элементов и вызывается это раз в пятилетку? А если это источник тормозов — профайлер такие вещи показывает kan>на раз.
Лучше, чтобы было предупреждение компилятора: "STL-контейнер, не string, передаётся по значению". А программист пускай решает: подавить это предупреждение или повысить до уровня ошибки.
Профайлер — run-time инструмент, изучает конкретный сценарий работы программы. Скажем, в домашних условиях программа тестируется с поверхностью, в которой 100 .. 1000 точек. Не тормозит. А пользователь, например, работает с поверхностью, в которой 100 000 точек. Идеология C++ такая: "что-то в compile-time лучше, чем что-то в run-time". Поэтому лучше узнать о проблеме от компилятора, а не от профайлера.
Я привёл пример, когда неявное копирование STL-контейнера вызвало сильное замедление работы программы. Замедление было замечено. Но люди на форуме смотрели на код в упор и не видели причину (на самом деле там была ещё одна причина: скобки glBegin/glEnd стояли внутри цикла; это заметили).
>> А>6. Вместо метода empty удобнее был бы метод с позитивным смыслом. >> ага kan>Фиолетово. Да и к тому же вариант с isEmpty или подобным — наиболее распространён.
На вкус и цвет товарищей нет. Чем меньше отрицаний, тем понятнее программа. А то иногда бывает код, как в песне Бориса Гребенщикова: "Я не знаю никого, кто не против".
У .NET-контейнеров (там они называются 'collections') я не обнаружил метода вроде empty.
kan>"if(cont.size())", "если обладает размером"
Здесь осторожнее. Есть такие реализации STL, что list::size работает за время O(N) (N — количество элементов списка).
>> А>7. Нельзя const_cast const_iterator в iterator. >> Ну, это, если и проблема, то не STL, а языка. kan>Я бы тоже не отказался, но не в таком виде, а в виде: kan>
kan>Cont cont = makeContainer();
kan>Cont::const_iterator iter = chooseSomeElement(cont); // chooseSomeElement берёт на вход const Cont&, что логично, и
kan>может вернуть только const_iterator
kan>Cont::iterator nonconst_iter = cont.make_nonconst(iter);// Вот такое хочу!
kan>cont.erase(nonconst_iter);// иначе, например, такое не сделать. :(
kan>
В данном случае, если есть возможность менять модуль с chooseSomeElement, то можно выкрутиться:
// не меняет Elements
Cont::iterator chooseSomeElement(Cont& Elements)
{
// вся работа здесь
...
}
// обёртка над не-const chooseSomeElement
Cont::const_iterator chooseSomeElement(const Cont& Elements)
{
// временно убрать константностьreturn chooseSomeElement(const_cast<Cont&>(Elements));
// iterator неявно преобразуется в const_iterator
}
Здравствуйте, Константин Л., Вы писали: А>>>>10.4. Конкатенация строк ПС>>Я имел в виду, что вместо: ПС>>
ПС>>DirPath + "\\" + FileName
ПС>>
ПС>>было бы оптимальнее писать: ПС>>
ПС>>Concat(DirPath, "\\", FileName)
ПС>>
КЛ>чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло.
operator+ бинарный. Поэтому в первом варианте сцепление строк делается в два этапа, примерно так:
То есть сколько плюсов, столько и вызовов. При этом создаются временные буферы (в данном случае один). До последнего operator+ char-ы хранятся во временных буферах. Только последний operator+ создаёт результирующий буфер и копирует туда char-ы.
Функция Concat, в идеале, "сколько-угодно-арная". В моей реализации (здесь
) используется класс StringBuf. При REALISTIC_STL_IMPL Concat не создаёт временных буферов, а сразу же создаёт результирующий буфер и копирует туда все char-ы.
Здравствуйте, kan, Вы писали:
kan>Пётр Седов wrote:
>> NULL-итератор >> То, что для пустого vector-а эти два итератора равны, проблем создавать >> не должно. >> Можно использовать boost::optional<iterator>, но лучше не усложнять. kan>Не понял, а чем std::vector<X>::const_iterator() не устраивает?
Если итератор — класс, а не указатель, то он так и останется неинициализированным. Для list-а, например, код:
list<int>::iterator it = list<int>::iterator(); // конструктор по умолчанию
*it = 10;
будет работать примерно так же, как и этот:
list<int>::iterator it; // конструктор по умолчанию
*it = 10;
В обоих случаях: если повезёт, будет громкий access violation; если не повезёт, будет тихая порча памяти.
'std::vector<X>::const_iterator()' — слишком многословно, 'NULL' — короче (или даже '0').
>> Я предупредил начинающих, что под size_t грабли лежат. А уж использовать его или нет — пускай сами решают. kan>Тут проблема не в STL, а знании начинающими арифметики и понимании операции вычитания. Всегда можно a == b — 1 преобразовать в a + 1 == b
Неужели есть программисты, не знающие арифметику? Проблема в том, что беззнаковая арифметика отличается от обычной в районе нуля. А знаковая арифметика для большого диапазона чисел по обе стороны от нуля совпадает с обычной. Даже если у Вас есть гигантская структура данных, требующая size_t, то скорее всего она изолирована в каком-то классе (например, менеджер памяти). И уж точно не стоит использовать STL для такой структуры данных. Представьте: string с буфером около 2 GB, возвращаете его из функции, при этом делается deep copy.
>> А>>5. Нельзя получить итератор по указателю на элемент контейнера за >> константное время. >> проигрывает ручному списку в стиле языка C: kan>Это называется intrusive containers
Я писал именно про STL, не про Boost.
>> А>>8. vector >> А>>8.1. Странное название у этого контейнера. >> RO>если еще учесть std::tr1::array = boost::array, то вообще весело станет >> RO>Это не так важно, все привыкли уже. >> + valarray >> Да, все привыкли к ещё одной программистской традиции, идущей вразрез с >> математикой. Одно из самых сложных действий в программировании — >> придумать хорошее имя для сущности. 'vector' — неудачное имя для >> динамического массива. Но это разговор для другого форума. kan>Я уже объяснял. Array — общее название массивов. Одномерный array называется vector (вспомни алгебру — там есть даже два понятия — вектор-столбец и вектор-строка), двумерный — matrix. В STL vector есть одномерный array, так что наоборот, всё очень точно.
Проблема не практическая, а философская. Уж лучше:
vector -> dynarray (обобщённый динамический массив)
valarray -> vector (для ВычМата, с расчётом на аппаратное ускорение)
Так когда-то и планировалось (я привёл историческую справку здесь
).
>> DirPath + "\\" + FileName >> было бы оптимальнее писать: >> Concat(DirPath, "\\", FileName) kan>Но в С++ нет функций с переменным числом аргументов (ellipsis не считается). И ради одной только операции конкатенации вводить такую штуку?..
Я сделал Concat-ы до 5-ти строк:
Пока хватало. Не хватит — допишу.
>> Насколько я знаю, компилятор C# делает такую замену автоматически. kan>Хаки? Или как там это работает?
Там тип string встроен в язык. Например, здесь
Здравствуйте, kan, Вы писали:
kan>Kluev wrote: >> kan>А зачем такой ужас писать? Чем банальный >> >> kan>for(size_t i = 0; i + 1 < vec.size(); i++) >> kan>не устраивает? >> Такая форма записи неестественная и не соотвествует ходу мышления. kan>Мышление переделай. Но запись абсолютно естественна — проверить, что выражение "i+1", которое мы используем как индекс не выходит за пределы размера вектора.
Ничего естесвенного в такой записи нет, это просто вынужденный воркэраунд вокруг беззнаковых типов.
Условие в цикле должно быть простым и ясным: итерировать отсюда и до сюда. "i+1" добавляет третье условие которое программист учитывать при чтении кода. Четвертое условие которе так же прийдется иметь ввиду чтобы не наступить на грабли — беззнаковость size_t.
kan> А что означает "i < vec.size() — 1", особенно в случае нулевого размера?
Означает итерировать все кроме последнего. Читается точно так же как и думается.
kan>Ещё прошу заметить, что понятие отрицательного индекса — вообще противоестественна, а поэтому может трактоваться по kan>разному. Например, в перле, обратиться по индексу "-2" — валидная операция, означает взять второй элемент с конца.
Пусть в перле делают как хотят, а в с++ индексация связана с адрессной арифметикой и поэтому должна иметь аналогичное поведение. В адресной арифметике отрицательные индексы совершенно естественны (указатель может указывать на середину массива)
>>> > Для того чтобы можно было писать по человечески. Если например двигаемся >>> > в произвольном направлении и с произвольным шагом, то к индексу >> kan>Для этого есть iterator. >> С итераторами неудобно работать. >> 1) они становятся невалидными после ресайза >> 2) программу неудобно отлаживать, т.к. итератор ничего не говорит ни о >> номере итерации, ни о индексе элемента в массиве.
kan>Индекс для вектора всегда "iter — vec.begin()"
В отладчике это как посмотреть? Или условный брейкпоинт поставить? В общем случае никак.
kan>В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".
Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — лучше юзать индексы, для интрузивных node-based контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.
Здравствуйте, Пётр Седов, Вы писали:
ПС>Здравствуйте, Константин Л., Вы писали: А>>>>>10.4. Конкатенация строк ПС>>>Я имел в виду, что вместо: ПС>>>
ПС>>>DirPath + "\\" + FileName
ПС>>>
ПС>>>было бы оптимальнее писать: ПС>>>
ПС>>>Concat(DirPath, "\\", FileName)
ПС>>>
КЛ>>чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло. ПС>operator+ бинарный. Поэтому в первом варианте сцепление строк делается в два этапа, примерно так: ПС>
ПС>То есть сколько плюсов, столько и вызовов. При этом создаются временные буферы (в данном случае один). До последнего operator+ char-ы хранятся во временных буферах. Только последний operator+ создаёт результирующий буфер и копирует туда char-ы. ПС>Функция Concat, в идеале, "сколько-угодно-арная". В моей реализации (здесь
) используется класс StringBuf. При REALISTIC_STL_IMPL Concat не создаёт временных буферов, а сразу же создаёт результирующий буфер и копирует туда все char-ы.
это все понятно, только вот это временные буферы меня не смущают, в отличие от ваших (вполне пригодных) велосипедов
Здравствуйте, Kluev, Вы писали:
kan>>В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".
K>Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — лучше юзать индексы, для интрузивных node-based контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>Здравствуйте, Kluev, Вы писали:
kan>>>В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".
K>>Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — лучше юзать индексы, для интрузивных node-based контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.
ЮБ>Ты себе представляешь stl без итераторов?
Цель итераторов — сделать перебор элементов в разных контейнерах одинаковым. Это больная идея т.к. контейнеры должны перебиратся наиболее нативным для них способом. Как например должен выглядеть итератор для многомерных массивов, кольцевых списков и деревьев? Многие контейнеры в концепцию итераторов просто не вписываются в результате чего программист вынужден пользоватся тем убогим набором который есть в stl. К томуже алгоритмы применимы не ко всем контейнерам и фактически единственным универсальным алгоритмом который подходит для всех является for_each. Но для этого существует более универсальный и могучий паттерн — визитор, который:
1) гораздо проще в реализации чем итератор
2) программы с его использованием получаются более элегантными
Третье преимущество в том что внутри container.clear(clear_func) пербор идет способом родным для контейнера, что существенно упрощает отладку.
Так же итераторы в стиле stl совершенно не подходят для перебора кольцевых контейнеров.
Т.к. в силу замкнутости их требуется итерировать не в диапазоне [begin, end), а в диапазоне [begin, last]
Elem *p, *last; // если p == last делаем полный кругfor (bool ok = true; ok; p = next(p))
{
ok = p != last;
// .....
}
Kluev wrote:
> Ничего естесвенного в такой записи нет, это просто вынужденный > воркэраунд вокруг беззнаковых типов. > Условие в цикле должно быть простым и ясным: итерировать отсюда и до > сюда. "i+1" добавляет третье условие которое программист учитывать при > чтении кода. Четвертое условие которе так же прийдется иметь ввиду чтобы > не наступить на грабли — беззнаковость size_t.
Почитай теоритические основы программирования. Предусловия, постусловия, инвариант цикла, схемы программ Янова, триады
Хоара. Тогда появится осмысление того чего ты пишешь и что является "естественным".
> kan> А что означает "i < vec.size() — 1", особенно в случае нулевого > размера? > Означает итерировать все кроме последнего. Читается точно так же как и > думается.
Какой элемент последний в пустом массиве?
> Пусть в перле делают как хотят, а в с++ индексация связана с адрессной > арифметикой и поэтому должна иметь аналогичное поведение. В адресной > арифметике отрицательные индексы совершенно естественны (указатель может > указывать на середину массива)
Кто сказал что связана? В stl не связана. Есть операция взятия элемента по индексу, индекс — неотрицательное число. Где
ты видел упоминание адресной арифметики в std::vector?
> kan>Индекс для вектора всегда "iter — vec.begin()" > В отладчике это как посмотреть? Или условный брейкпоинт поставить? В > общем случае никак.
Ну это проблемы отладчика, а не stl. А вообще говоря можно: "iter._Myptr — vec._Myfirst" для MSVS7.1 с родным STL.
> kan>В общем, какие-то надуманные проблемы, чаще всего возникающие от > недопонимания понятия "итератор". > Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — > лучше юзать индексы, для интрузивных node-based контейнеров достаточно > знать указатель на элемент. Лишние сущности не нужны.
Ты вообще понимаешь смысл понятия "generic programming"? Смысл абстракции?
Видишь ли, stl основывается на некоторых теоретических аспектах, а не только на общеизвестных практических приёмчиках.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Kluev wrote:
> ЮБ>Ты себе представляешь stl без итераторов? > Цель итераторов — сделать перебор элементов в разных контейнерах > одинаковым. Это больная идея т.к. контейнеры должны перебиратся наиболее > нативным для них способом. Как например должен выглядеть итератор для > многомерных массивов, кольцевых списков и деревьев? Многие контейнеры в
Делается просто — несколько типов итераторов. Классический пример — begin-end/rbegin-rend. Для дерева можно 2 типа
сделать — обход в ширину и обход в глубину.
Т.е. функции, возвращающие итераторы могут быть даже с аргументами, например, задать по какой "кривой" обойти
многомерный массив.
> концепцию итераторов просто не вписываются в результате чего программист > вынужден пользоватся тем убогим набором который есть в stl. К томуже > алгоритмы применимы не ко всем контейнерам и фактически единственным > универсальным алгоритмом который подходит для всех является for_each. Но > для этого существует более универсальный и могучий паттерн — визитор, > который: > > 1) гораздо проще в реализации чем итератор > 2) программы с его использованием получаются более элегантными
Требует задания функтора. Всегда. А это не всегда элегантно.
Не позволяет иметь несколько итераторов, позволяющих обходить контейнер в разном порядке одновременно.
> Третье преимущество в том что внутри container.clear(clear_func) пербор > идет способом родным для контейнера, что существенно упрощает отладку.
Какой способ является родным для дерева? Да даже для того же массива? Почему от начала к концу, а не наоборот? Или с
середины к краям?
> Так же итераторы в стиле stl совершенно не подходят для перебора > кольцевых контейнеров. > Т.к. в силу замкнутости их требуется итерировать не в диапазоне [begin, > end), а в диапазоне [begin, last]
[begin, last] никак не позволяет задавать пустые интервалы, и никак это не обойти, и это является наиболее важным. Тем
более не надо делать замкнутый итератор единственно доступным для контейнера. Пусть это будет обычный std::list, просто
для него создать ещё один тип итератора, который будет замыкаться. Но это не запрещает при необходимости использовать
старые добрые begin/end. Можно написать метод, возвращающий [first, last) для кольцевого контейнера, притом first будет
совпадать с указанным "началом" кольца.
На самом деле есть более интересная абстракция boost::range.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan, Вы писали:
kan>Kluev wrote:
>> Ничего естесвенного в такой записи нет, это просто вынужденный >> воркэраунд вокруг беззнаковых типов. >> Условие в цикле должно быть простым и ясным: итерировать отсюда и до >> сюда. "i+1" добавляет третье условие которое программист учитывать при >> чтении кода. Четвертое условие которе так же прийдется иметь ввиду чтобы >> не наступить на грабли — беззнаковость size_t. kan>Почитай теоритические основы программирования. Предусловия, постусловия, инвариант цикла, схемы программ Янова, триады kan>Хоара. Тогда появится осмысление того чего ты пишешь и что является "естественным".
Отсылать к литературе — это плохая идея. Если хочешь продвинуть мысль то лучше изложи суть идеи, преимущества, недостатки. Мнения классиков меня не волнуют.
>> kan> А что означает "i < vec.size() — 1", особенно в случае нулевого >> размера? >> Означает итерировать все кроме последнего. Читается точно так же как и >> думается. kan>Какой элемент последний в пустом массиве?
Фраза итерировать все кроме последнего сотоит из двух частей.
1) итерировать все
2) кроме последнего
В пустом массиве элементов нет значит вторая часть фразы нас уже не интересует. логика проста и очевидна.
>> Пусть в перле делают как хотят, а в с++ индексация связана с адрессной >> арифметикой и поэтому должна иметь аналогичное поведение. В адресной >> арифметике отрицательные индексы совершенно естественны (указатель может >> указывать на середину массива) kan>Кто сказал что связана? В stl не связана. Есть операция взятия элемента по индексу, индекс — неотрицательное число. Где kan>ты видел упоминание адресной арифметики в std::vector?
Ноги растут из языка. Если язык допускает отрицательный индекс для встроенного массива (которым в общем случае является указатель), значит контейнеры должны соотвествовать этому поведению, а не брать элементы с конца и т.п. К тому же кто сказал что контейнер должен быть обязательно от 0 до N? Если мне понадобится контейнер от -N до N то не думаю что меня будут мучать философские вопросы об отрицательных индексах и т.п.
>> kan>Индекс для вектора всегда "iter — vec.begin()" >> В отладчике это как посмотреть? Или условный брейкпоинт поставить? В >> общем случае никак.
kan>Ну это проблемы отладчика, а не stl. А вообще говоря можно: "iter._Myptr — vec._Myfirst" для MSVS7.1 с родным STL.
Да... юзабилити из этого решения так и прет
>> kan>В общем, какие-то надуманные проблемы, чаще всего возникающие от >> недопонимания понятия "итератор". >> Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — >> лучше юзать индексы, для интрузивных node-based контейнеров достаточно >> знать указатель на элемент. Лишние сущности не нужны.
kan>Ты вообще понимаешь смысл понятия "generic programming"? Смысл абстракции? kan>Видишь ли, stl основывается на некоторых теоретических аспектах, а не только на общеизвестных практических приёмчиках.
Ты маркетолог или программист? Мне совершенно безразлично на чем основывается стл, главное то что она неюзабельная. Я пользователь библиотеки и меня интересуют в первую очередь удобство использования, отладки и другие прикладные аспекты, а не красивые идеи.
Здравствуйте, kan, Вы писали:
kan>Kluev wrote:
>> ЮБ>Ты себе представляешь stl без итераторов? >> Цель итераторов — сделать перебор элементов в разных контейнерах >> одинаковым. Это больная идея т.к. контейнеры должны перебиратся наиболее >> нативным для них способом. Как например должен выглядеть итератор для >> многомерных массивов, кольцевых списков и деревьев? Многие контейнеры в kan>Делается просто — несколько типов итераторов. Классический пример — begin-end/rbegin-rend. Для дерева можно 2 типа kan>сделать — обход в ширину и обход в глубину.
Не юзабельно. Т.к. рекурсия в данном случае проще и лучше.
kan>Т.е. функции, возвращающие итераторы могут быть даже с аргументами, например, задать по какой "кривой" обойти kan>многомерный массив.
Опять же неюзабельно. Во превых такой итератор прийдется писать, во вторых зачем? Если нужен какой-то путь в массиве, то отдельный массив с индексами то что нужно. Просто и в написании и в отладке.
>> концепцию итераторов просто не вписываются в результате чего программист >> вынужден пользоватся тем убогим набором который есть в stl. К томуже >> алгоритмы применимы не ко всем контейнерам и фактически единственным >> универсальным алгоритмом который подходит для всех является for_each. Но >> для этого существует более универсальный и могучий паттерн — визитор, >> который: >> >> 1) гораздо проще в реализации чем итератор >> 2) программы с его использованием получаются более элегантными kan>Требует задания функтора. Всегда. А это не всегда элегантно.
Не всегда. в контейнере просто заводятся функуци с визитором и без.
kan>Не позволяет иметь несколько итераторов, позволяющих обходить контейнер в разном порядке одновременно.
Для этого есть обычные циклы которые как раз для этих вещей и предназначены. Чтобы ходить как хочешь и куда хочешь.
>> Третье преимущество в том что внутри container.clear(clear_func) пербор >> идет способом родным для контейнера, что существенно упрощает отладку. kan>Какой способ является родным для дерева? Да даже для того же массива? Почему от начала к концу, а не наоборот? Или с kan>середины к краям?
Для дерева родной способ рекурсия, для массива и списка итерация. Иетартор всегда итерация, а значит написать итератор например для дерева может оказатся весьма непростой задачей. for_each не должен зависить от порядка элементов, а если требуются какие-то особые случаи то надо делать обычный цикл.
>> Так же итераторы в стиле stl совершенно не подходят для перебора >> кольцевых контейнеров. >> Т.к. в силу замкнутости их требуется итерировать не в диапазоне [begin, >> end), а в диапазоне [begin, last] kan>[begin, last] никак не позволяет задавать пустые интервалы, и никак это не обойти, и это является наиболее важным. Тем kan>более не надо делать замкнутый итератор единственно доступным для контейнера. Пусть это будет обычный std::list, просто kan>для него создать ещё один тип итератора, который будет замыкаться.
Это как? На каждой итерации проверять не в конце ли мы и если в конце то переходить на первый элемент? Значит ради идей уже пожертвовали удобством и отладкой, а теперь вот еще и на производительность плевать. Не самая лучшая идея. Более того такое решение все равно будет более неудобным чем специализированный контейнер.
Kluev wrote: > kan>Делается просто — несколько типов итераторов. Классический пример — > begin-end/rbegin-rend. Для дерева можно 2 типа > kan>сделать — обход в ширину и обход в глубину. > Не юзабельно. Т.к. рекурсия в данном случае проще и лучше.
Юзабельно. Это фактически просто развернутая рекурсия.
> kan>Т.е. функции, возвращающие итераторы могут быть даже с аргументами, > например, задать по какой "кривой" обойти > kan>многомерный массив. > Опять же неюзабельно. Во превых такой итератор прийдется писать, во > вторых зачем? Если нужен какой-то путь в массиве, то отдельный массив с > индексами то что нужно. Просто и в написании и в отладке.
Зачем писать? Просто создается нужный функтор.
Из личного опыта — кроме как итераторами трехмерный разреженный массив
обходить все равно удобно не получится.
>> > 1) гораздо проще в реализации чем итератор >> > 2) программы с его использованием получаются более элегантными > kan>Требует задания функтора. Всегда. А это не всегда элегантно. > Не всегда. в контейнере просто заводятся функуци с визитором и без.
Визитор сам по себе неудобен. Так как в функции-визиторе нельзя получить
информацию о следующем или предидущем члене.
Здравствуйте, kan, Вы писали:
>> for(i = 0, j = vec.size()-1; i < j; i++)
>> Со знаковыми типами вот такой код будет нормально работать, а с >> бесзнаковыми i,j при vec.size()==0 будут грабли. kan>А зачем такой ужас писать? Чем банальный kan>for(size_t i = 0; i + 1 < vec.size(); i++) kan>не устраивает?
Здесь ты неправ. Вот пару дней назад на топкодере была задача, связанная с выпуклостью функции, заданной массивом значений. Написал на листочке формулу, перевел в Ц++. Вот что вышло:
С математической точки зрения всё правильно. Но если вдруг value_type(x) = unsigned, получим сюрпрайз.
Или другая задача. Есть много чисел (могут быть и <0), есть число M. Для каждого значения из [0, M) надо знать, сколько чисел из исходного набора имеют такой остаток при делении на M.
Kluev wrote:
>> > ЮБ>Ты себе представляешь stl без итераторов? >> > Цель итераторов — сделать перебор элементов в разных контейнерах >> > одинаковым. Это больная идея т.к. контейнеры должны перебиратся наиболее >> > нативным для них способом. Как например должен выглядеть итератор для >> > многомерных массивов, кольцевых списков и деревьев? Многие контейнеры в > kan>Делается просто — несколько типов итераторов. Классический пример — > begin-end/rbegin-rend. Для дерева можно 2 типа > kan>сделать — обход в ширину и обход в глубину. > Не юзабельно. Т.к. рекурсия в данном случае проще и лучше.
Причём тут рекурсия? Рекурсия — не алгоритм, а метод (способ) реализации алгоритма. "обход в ширину и обход в глубину" —
два разных алгоритма обхода дерева, которые могут быть (а могут и не быть) реализованы с помощью рекурсии.
> kan>Т.е. функции, возвращающие итераторы могут быть даже с аргументами, > например, задать по какой "кривой" обойти > kan>многомерный массив. > Опять же неюзабельно. Во превых такой итератор прийдется писать, во > вторых зачем? Если нужен какой-то путь в массиве, то отдельный массив с > индексами то что нужно. Просто и в написании и в отладке.
В смысле обход элементов многомерного массива. Например, можно обходить вначале 1-е, потом 2-е, потом 3-е измерение. А
можно вначале 3-е, потом 1-е, потом 2-е. И т.д. Т.е. куча разных вариантов обхода элементов массива. Можно сделать
метод, который будет выдавать "обходчик массива" (итератор, если по-русски) в зависимости от того, какой способ мы хотим
в данный момент использовать.
>> > 1) гораздо проще в реализации чем итератор >> > 2) программы с его использованием получаются более элегантными > kan>Требует задания функтора. Всегда. А это не всегда элегантно. > Не всегда. в контейнере просто заводятся функуци с визитором и без.
Не понял.
> kan>Не позволяет иметь несколько итераторов, позволяющих обходить > контейнер в разном порядке одновременно. > Для этого есть обычные циклы которые как раз для этих вещей и > предназначены. Чтобы ходить как хочешь и куда хочешь.
Объясни, что является "обычным циклом" при обходе vector? а deque? а list? И почему я должен переписывать этот цикл,
если я вдруг поменял list на vector?
>> > Третье преимущество в том что внутри container.clear(clear_func) пербор >> > идет способом родным для контейнера, что существенно упрощает отладку. > kan>Какой способ является родным для дерева? Да даже для того же > массива? Почему от начала к концу, а не наоборот? Или с > kan>середины к краям? > Для дерева родной способ рекурсия, для массива и списка итерация.
Бред. Что такое рекурсия для дерева? Кто мне помешает обойти дерево итерацией, а массив рекурсией?
> Иетартор всегда итерация, а значит написать итератор например для дерева > может оказатся весьма непростой задачей. for_each не должен зависить от > порядка элементов, а если требуются какие-то особые случаи то надо > делать обычный цикл.
Может зависеть, может не зависеть. Да и не только ради for_each задумывалось всё это дело.
>> > Так же итераторы в стиле stl совершенно не подходят для перебора >> > кольцевых контейнеров. >> > Т.к. в силу замкнутости их требуется итерировать не в диапазоне [begin, >> > end), а в диапазоне [begin, last] > kan>[begin, last] никак не позволяет задавать пустые интервалы, и никак > это не обойти, и это является наиболее важным. Тем > kan>более не надо делать замкнутый итератор единственно доступным для > контейнера. Пусть это будет обычный std::list, просто > kan>для него создать ещё один тип итератора, который будет замыкаться. > Это как? На каждой итерации проверять не в конце ли мы и если в конце то > переходить на первый элемент? Значит ради идей уже пожертвовали
Как реализуешь, так и будет. Итератор по этому поводу ничего не требует.
Контейнер может возвращать кольцевой итератор и пару итераторов, которые будут [first,last).
> удобством и отладкой, а теперь вот еще и на производительность плевать. > Не самая лучшая идея. Более того такое решение все равно будет более > неудобным чем специализированный контейнер.
Библиотека stl проектировалась именно так, чтобы можно было делать эффективные имплементации... так что непонятно о чём ты?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Долго пытался не влезать в эту дискуссию, но все же попытаюсь изложить собственное мнение.
(Ибо пятница, вечер и лениво делать что-то умное. К тому же ребилд %)).
Читая эту уже порядком затянувшуюся ветку, все больше и больше убеждаюсь, что
все "Минусы STL" и "Проблемы STL контейнеров" кроются в закостенелости мышления.
Большинство упреков (есть, конечно, и минусы, без этого нельзя) появляются
вследствие не(до)понимания каких-то концепций.
К сожалению, это характерно не только для новичков, но и для маститых программистов
которые уже привыкли всюду писать свои велосипеды и не доверяют стандартной библиотеке.
Это также объясняется тем, что некоторые воспринимают C++ только как синтаксическое
расширение C, т.е. не принимают (не понимают или даже не пытаются понять) тех парадигм,
которые делают С++ высокоуровневым языком.
Да, можно успешно писать на С++ не используя стандартную библиотеку,
ровно как писать на Java и использовать собственные контейнеры и алгоритмы.
Но осмысленно ли это?
Те, кто говорят, что «STL плоха, ибо я ее не использую», скорей всего просто не разобрались STL.
Те, кто говорят, что «STL не юзабельная», просто не видели больших проектов, построенных с использованием STL.
(В продукте над которым я работаю около 200 проектов. Все построены на COM + STL. Как это не удивительно, но
юзать MFC никому даже в голову не пришло %)).
Те же, кто говорят, что STL бедна, ибо не реализует B-деревья, топологическую сортировку,
фибоначиву кучу, алгоритмы Дейкстры, Форда-Фалкерсона, Джонсона…, не решает задачи
о рюкзаке, коммивояжере, максимальном потоке…, не предоставляет средства для работы с сокетами,
USB, сотовыми телефонами, Wi-Fi и т.д. требуют от стандартной библиотеки слишком много.
Некоторые думают, что STL жутко тормозная и экономят каждую инструкцию в тех местах, где это никому
не нужно (пресловутая преждевременная оптимизация). К примеру, в GUI.
В действительности, даже такие структуры как std::map<string> достаточно быстры,
что позволяют писать высокоточные профайлеры.
Ну, а те, кого не интересует мнения классиков, обречены вечно наступать на свои же грабли.
Ибо, как известно, дурак учится на своих ошибках, а умный на чужих %).
К сожалению, такой порядок дел не изменить в силу все той же закостенелости мышления и нежелании что-либо менять.
Поэтому, ИМХО, данная ветка уже давно перешла в ранг холиворов вроде C vs C++.
Остается только надеяться, что такое положение дел положительно скажется на развитии стандартной библиотеки.
--
С уважением, Александр
С уважением, Александр
Re: минусы STL
От:
Аноним
Дата:
08.09.06 18:34
Оценка:
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
Здравствуйте, Alex_Avr, Вы писали: A_A>Здравствуйте, Аноним, Вы писали:
А>>3. Нет понятия 'NULL-итератор'. В качестве итератора, "ссылающегося в никуда", обычно используют Container.end(). Но вместо кода: А>>
А>>Особенно, если такого кода много. Вариант с NULL-итератором лучше по всем показателям: А>>
Быстрее читается.
A_A>Как-то не было проблем с чтением.
'm_pServer->ItemsEnd()' — три слова.
'NULL' — одно слово.
Я вариант с 'NULL' читаю быстрее. Когда вижу слово 'NULL', в голове сразу же появляется мысль: "нет объекта". Нужно чуть больше времени, чтобы понять, что такое 'm_pServer->ItemsEnd()'.
А>>
Быстрее пишется.
A_A>В современных IDE разницы практически нет.
В современных IDE программисты часто ускоряют написание ' != NULL'. А вот ускорить написание ' != m_pServer->ItemsEnd()' сложнее из-за большого количества вариантов.
А>>
Быстрее работает.
А>>
Порождает меньше машинных инструкций.
A_A>Не факт, компилятор может встроить тело end () в место вызова.
Я проверил в MSVC6 Release. Контейнер — list. Вариант с end-итератором:
00401505 mov eax,dword ptr [esi]
00401507 mov ecx,dword ptr [eax+4]
0040150A mov dword ptr [esi+4],ecx
0040150D pop esi
}
}
0040150E ret
--- No source file ------------------------------------------------------------
0040150F nop
Компилятор действительно встроил оба вызова Server::ItemsEnd (возвращает 'm_Items.end()'). Размер функции: 0x0040150F — 0x004014F0 = 31 байт. Вариант с NULL-итератором:
void Client::ReleaseRecentItem()
{
004014F0 push esi
004014F1 mov esi,ecx
if (m_itRecentItem != NULL)
004014F3 mov eax,dword ptr [esi+4]
004014F6 test eax,eax
004014F8 je Client::ReleaseRecentItem+19h (00401509)
--- No source file ------------------------------------------------------------
0040150B nop
Размер функции: 0x0040150B — 0x004014F0 = 27 байт. Разница действительно мизерная (4 байта). Время работы, скорее всего, тоже почти одинаково (не мерял). Но в данном случае размер ассемблерного кода и скорость работы на втором плане. В первую очередь, NULL-итераторы дают:
Возможность инициализировать итератор без доступа к контейнеру. Неинициализированный итератор опасен. Если его случайно использовать, то есть риск тихо испортить память.
Улучшение читаемости кода.
A_A>Итераторы могут быть классами, а не простыми указателями (как в STLPort в отладочном билде), в этом случае такой поход работать не будет.
Обычно итераторы — это обёртки над указателями. Поэтому легко добавить поддержку NULL-итераторов. Например, для list-а:
А>>5. Нельзя получить итератор по указателю на элемент контейнера за константное время. A_A><код поскипан> А>>Желательно, чтобы код, выделенный жирным, работал за константное время. A_A>А кто сказал, что это возможно для любых итераторов и любых контейнеров?
Никто. Но для некоторых возможно:
Для vector-а это не нужно (realloc аннулирует указатель на элемент), но можно сделать уже сейчас:
int Index = pElem - &Vec[0];
vector<...>::iterator itElem = Vec.begin() + Index;
assert(&*itElem == pElem);
Для vector<bool> нельзя получить указатель на элемент.
Для node-based контейнеров (list, map) итератор — это обёртка над Node*. Адреса pNodе и pElem различаются на константу (смещение Elem в структре Node). Поэтому можно сделать быстрый iterator_from_pointer.
Для deque нельзя получить итератор по указателю на элемент за константное время. deque — это не node-based контейнер, а массив указателей на массивы.
Для hash_map зависит от того, как он сделан. Обычно hash_map содержит массив "вёдер" (bucket). В каждом ведре — список элементов, чьё hash-значение равно индексу ведра. Поэтому индекс ведра можно восстановить по элементу (вычислив hash-значение). Например, в SGI STL (файл stl_hashtable.h):
Итератор содержит указатель на hash-таблицу (_M_ht) и указатель на node (_M_cur). Других значений нет. После последнего node-а в ведре нужно перейти к следующему ведру. Итератор восстанавливает индекс ведра по элементу (вычисляя hash-значение):
При переходе к следующему ведру итератор использует некоторые члены hash-таблицы. _M_buckets — это vector<_Node*, ...> (массив вёдер). _M_bkt_num — это функция, вычисляющая hash-значение (обёртка над функциональным объектом _M_hash). Для такой реализации можно сделать быстрый iterator_from_pointer:
Здесь не нужно восстанавливать индекс ведра, потому что итератор его не хранит (возможно, чтобы при resize-е hash-таблицы существующие итераторы остались в силе). Если бы итератор хранил индекс ведра, я бы добавил строчку:
С натяжкой можно сказать, что это работает за константное время (по крайней мере не зависит от количества элементов в hash-таблице).
В STLport 4.5.3 то же самое (она основана на SGI STL). Там есть одна интересная деталь: hash-таблица использует что-то вроде vector<void*> для массива вёдер, чтобы уменьшить разбухание (ассемблерного) кода (code bloat).
Можно не вычислять hash-значение при переходе к следующему ведру, а хранить hash-значения в node-ах. Так делает CMap в MFC 4.2:
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
class CMap : public CObject
{
protected:
// Associationstruct CAssoc
{
CAssoc* pNext;
UINT nHashValue; // needed for efficient iteration
KEY key;
VALUE value;
};
...
};
Можно поступить так же, как с list::size: стандарт рекомендует, чтобы iterator_from_pointer работал за константное время, но реализация может работать за время O(N) (N — количество элементов в контейнере).
А>>9. list А>>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны). Стандарт рекомендует ("should"), чтобы list::size работал за константное время, но выбор оставлен на усмотрение реализации STL. Соответственно, есть "странные" реализации STL (например, SGI STL, раздел "Why is list<>::size() linear time?"), в которых size вычисляется, а не хранится. То есть реализация size-а пробегает по всему списку и таким образом узнаёт количество элементов. А>>В MFC CList::GetCount работает за константное время: А>>
А>>
А>>template<class TYPE, class ARG_TYPE>
А>>AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
А>> { return m_nCount; }
А>>
. A_A>То, что в одной из реализаций STL list::size () имеет линейную сложность еще ни очем не говорит.
Это говорит о том, что стоит осторожно обращаться с list::size. Например, выносить за тело цикла, если список не меняется в ходе цикла. Если меняется, то можно запросить list::size один раз до цикла, а в ходе цикла вручную отслеживать длину списка. Правильность ручной длины списка можно проверять assert-ом.
Кстати, STLport 4.5.3 тоже "странная" (файл _list.h):
A_A>Да и есть ли в CList аналог list::splice ()?
Нет. В MFC 4.2 каждый CList имеет личный менеджер памяти (pool). Поэтому нельзя дёшево перетащить элементы из одного списка в другой. Можно только дорого:
template<...>
void CList<...>::AddHead(CList* pNewList)
{
...
// add a list of same elements to head (maintain order)
POSITION pos = pNewList->GetTailPosition();
while (pos != NULL)
AddHead(pNewList->GetPrev(pos));
}
template<...>
void CList<...>::AddTail(CList* pNewList)
{
...
// add a list of same elements
POSITION pos = pNewList->GetHeadPosition();
while (pos != NULL)
AddTail(pNewList->GetNext(pos));
}
А>>9.2. Неизвестен порядок уничтожения элементов в деструкторе list-а. Специализированный менеджер памяти, работающий как stack, может требовать, чтобы блоки памяти освобождались в обратном порядке. Я проверил две реализации STL: MSVC6 STL и Rogue Wave STL 2.1.1 (поставляется вместе с BCB5). В обеих ~list уничтожает элементы в прямом порядке. То есть если я наполняю list push_back-ами, то stack-овый менеджер памяти использовать нельзя. A_A>А когда это нужно?
Например, есть кратковременный список, живущий в блоке кода. Если функция вызывается часто (например, при resize-е окна), то желательно оптимизировать распределение памяти. Можно использовать alloca, но это опасно (риск получить stack overflow). Лучше использовать stack-овый менеджер памяти. Это редкий случай, когда оптимизация почти не усложняет код. Вместо:
A_A>На мой вгляд, закладываться на особенности внутренней реализации контейнера не есть правильно.
Теоретически, ~list может уничтожать элементы в случайном порядке:
template<typename TElem, ...>
list<TElem, ...>::~list()
{
while (!empty())
{
int Index = rand() % size();
iterator it = begin();
advance(it, Index);
erase(it);
}
// что-нибудь ещё
...
}
Фактически, выбор маленький: уничтожать элементы в прямом порядке или в обратном. Гарантия на этот счёт могла бы помочь при оптимизации.
А>>9.3. push_front и push_back не возвращают итератор на ново-вставленный элемент. Мелочь, а неудобно. В будущем это вполне можно исправить, старый код менять не придётся. Пока, можно сделать обёртку над list-ом: А>>
A_A>Гм, а почему нельзя просто использовать list::front () и list::back ()?
front/back возвращают ссылку на элемент. Иногда нужно добавить элемент в конец списка и получить итератор на ново-вставленный элемент. Например, здесь
A_A>Мне кажется, что операции получения итераторов на элементы и вставка разделены не просто так,
Разделены? list::insert, вставляющий один элемент, возвращает итератор на ново-вставленный элемент. Чем push_front/push_back хуже?
A_A>а для того, чтобы можно было гарантировать предсказуемое состояние A_A>программы в случае, если итератор является классом и при его копировании A_A>может вылететь исключение:
Итератор list-а — это всегда класс. Но это всего лишь тонкая обёртка над указателем на node.
A_A>
A_A>class A { int n; };
A_A>list<A> list_of_A;
A_A>list<A>::iterator it = list_of_A.push_back (A ()); // если здесь вылетело исключение о нехватки памяти, как
A_A> // определить произошло это при вставке элемента в контейнер
A_A> // или при копировании итератора? И в каком состоянии
A_A> // теперь находится list_of_A, был ли в него добавлен
A_A> // элемент?
A_A>
Вряд ли конструктор копирования итератора бросает исключение о нехватке памяти. Зачем итератору запрашивать память? А вот allocator::allocate может бросить исключение о нехватке памяти. В этом случае состояние list_of_A не изменится (список останется пустым).
Обычно итераторы копируются дёшево и без исключений. Если методы итератора и бросают исключения, то это скорее что-нибудь вроде logic_error (а не bad_alloc). Например, усердная реализация STL может ловить сравнение итераторов от разных list-ов (это логическая ошибка).
А>>10. string А>>10.1. Если программа много работает с текстом, то string (или его аналог) — ходовой тип. При этом желательно, чтобы неявное копирование string-а было дешёвым. Для этого реализация string-а может использовать разделяемый (между несколькими string-ами) буфер с подсчётом ссылок. A_A>Сейчас , на сколько я знаю, отходят от использования COW при реализации std::string из-за проблем с многопоточностью,
Многие программы однопоточны. Поэтому хорошо бы иметь выбор:
// заголовочный файл <string>#ifdef _MT // = multi thread
// многопоточная реализация basic_string-а (не считает ссылки)#else// однопоточная реализация basic_string-а (считает ссылки)#endif
Я не люблю, когда такой выбор сделан за меня.
A_A>к тому же это только одна из возможных реализаций.
По большому счёту все реализации string-а делятся на две группы:
С подсчётом ссылок.
Без подсчёта ссылок, vector-стиль. Реализация может использовать фиксированный буфер для коротких последовательностей, но для длинных она динамически запрашивает память. При этом неявное копирование дорого и может бросить исключение (если не хватит памяти). Это не очень хорошо, если string — элемент STL-контейнера (например, list<string>). Страуструп в книге "Язык программирования C++" (третье издание) в разделе 17.1.4 ("Требования к элементам" (STL-контейнеров)) пишет по этому поводу:
Например, операция копирования, генерирующая исключения, может оставить какой-нибудь элемент лишь частично скопированным. Она может оставить даже сам контейнер в состоянии, которое потом принесёт неприятности. Такие операции копирования сами по себе являются плохо спроектированными (§ 14.4.6.1).
То есть желательно, чтобы неявное копирование либо было запрещено, либо было дёшево. Дорогое неявное копирование подозрительно.
A_A>Все-таки как-то странно подгонять интерфейс под реализацию.
В том то и дело, что интерфейс string-а подогнан под реализацию в vector-стиле (без подсчёта ссылок). Есть "плохие" методы, возвращающие не-const ссылку на буфер (например, не-const operator[]). Если реализация считает ссылки, то внешняя не-const ссылка на буфер сильно ограничивает свободу string-а, он вынужден уважать эту ссылку до realloc-а или до деструктора. "Плохой" метод делает copy-on-write (возможно, холостой) и жёстко привязывает буфер к одному единственному string-у. Привязанный буфер не может разделяться между несколькими string-ами. При этом реализация деградирует до vector-стиля и неявное копирование дорожает. К сожалению, интерфейс string-а недостаточно отделён от реализации, он ставит палки в колёса реализации, считающей ссылки.
У MFC-шного CString-а тоже есть методы, возвращающие не-const ссылку на буфер. Но. Во-первых, очень тяжело случайно вызвать методы GetBuffer, GetBufferSetLength и LockBuffer (в отличие от не-const string::operator[]). Во-вторых, есть парные методы (ReleaseBuffer и UnlockBuffer), аннулирующие ранее выданный указатель. Такой подход более дружелюбен к подсчёту ссылок (в MFC 4.2 CString считает ссылки).
A_A>С другой стороны, может было бы лучше как в Java реализовать отдельно классы для неизменяемых строк и строк с возможностью изменения.
Конечно! Разумно разделить класс string на два: string2 и string2_builder, которому и передать всё изобилие методов append, insert, erase и replace; можно ещё добавить prepend. У string2 только базовые способы наполнения: конструкторы, assign и прямой доступ к буферу на запись.
А>>10.2. Нет завершающего '\0'. Вот такой код: А>>
А>>string Text = "abc";
А>>assert(Text[3] == '\0');
А>>
А>>содержит логическую ошибку, так как '3' является ошибочным индексом для string-а с length = 3. Усердная реализация STL, проверяющая индекс, обнаружит это и сообщит об ошибке (с помощью assert-а или исключения). Если реализация STL беспечная (не проверяет индекс), то фактически код будет работать, так как '\0' в конец обычно ставят (чтобы иметь быструю реализацию метода c_str). A_A>Используйте правильную STL A_A>Вообще-то не понял, в чем проблема. Насколько я знаю, в string обычно хранится именно NULL terminating строка. A_A>Где это не так?
Это везде так, но официально доступ к завершающему '\0' запрещён. Усердная реализация operator[], проверяющая индекс, воспримет доступ к завершающему '\0' как ошибку. Это повлечёт сообщение от assert-а или исключение (вроде out_of_range).
А>>Иногда завершающий '\0' удобен при parsing-е. A_A>Парсинг это частная задача и подгонять std::string под вашу конкретную его реализацию несколько станно.
При проектировании строкового класса очень разумно учитывать потребности parsing-а. Подгонять ничего не надо: достаточно официально разрешить доступ к завершающему '\0'.
A_A>Целесообразнее, IMHO, парсинг проводить с помощью алгоритмов, регулярных выражений или конечных автоматов.
Или с помощью готовых parser-ов (например, XML-parser). Можно использовать генераторы parser-ов (например, YACC, Lex). Но иногда это стрельба из пушки по воробьям. В простых случаях (как IsValidMethodName) лучше не усложнять код.
А>>В будущем доступ к завершающему '\0' может быть разрешён. A_A>Ага, что бы пользователь класса сам мог этот нуль затереть и получить AV или SEGFAULT при вызове std::string::find например
Последовательность char-ов string-а может содержать '\0'. Поэтому, в отличие от strchr, string::find не использует завершающий '\0' как барьер, а честно проверяет граничное условие. Затерев завершающий '\0', программист повредит только себе: c_str будет возвращать указатель на буфер, не завершающийся '\0'.
В идеале, хорошо бы чётко разделить чтение и запись:
template<typename TChar, ...>
class basic_string
{
...
// можно читать завершающий '\0'
TChar operator[](size_type Index) const
{
assert(Index <= length());
...
}
// нельзя писать в завершающий '\0'void set_at(size_type Index, TChar c)
{
assert(Index < length());
...
}
...
};
А>>10.3. Нет прямого доступа к буферу на запись. A_A>Это позволяет string-у самому управляться со своими данными, что предотвращает проблемы некорректного с ними отношения со стороны пользователя.
Прямой доступ к буферу на запись — низкоуровневая возможность. Она позволяет быстро наполнить string без промежуточного буфера, в том числе с помощью C-style API. Эта возможность нужна в первую очередь создателям высокоуровневых библиотек для эффективной реализации. Новички таким не занимаются, они используют эти самые высокоуровневые библиотеки.
А защищаться от ошибочного использования надо не урезанием функциональности, а отладочными проверками.
А>>
A_A>Ну да, а если пользователь забыл вызвать resize () или указал недостаточный размер?
Отсутствие прямого доступа к буферу на запись не защищает от такой ошибки. С промежуточным буфером точно так же есть риск указать недостаточную длину:
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
vector<char> Buf(Len); // программист забыл '+ 1' для завершающего '\0'
::GetWindowText(hEditControl, &Buf[0], Len + 1);
Text.assign(&Buf[0], Len);
}
A_A>Кроме того, как тогда быть с выделенным: А>>Фактически это работает, но стандарт не гарантирует, что string хранит char-ы последовательно в одном массиве (кстати, для vector-а такая гарантия есть (не считая vector<bool>)). Теоретически, string может хранить char-ы задом наперёд или в нескольких массивах (как deque).
Такая возможность дана string-у для оптимизации (например, конкатенации). Но для оптимизации нужно знать особенности программы. string их не знает, это универсальный класс. Поэтому все известные мне реализации string-а не выпендриваются и хранят char-ы в одном монолитном буфере. Реализацию string-а в deque-стиле я видел только на картинке в книге Страуструпа "Язык программирования C++" (третье издание) в разделе 17.1.3 ("Представление" (STL-контейнеров)). Даже если доведётся использовать такую реализацию, то можно выбрать вариант GENERIC_STL_IMPL (с промежуточным буфером). Но скорее всего не доведётся, так как есть движение в сторону гарантии непрерывности char-ов в string-е.
Кстати, конкатенацию строк можно оптимизировать гораздо проще, заменив бинарный operator+ на "сколько-угодно-арную" функцию Concat. Об этом — пункт 10.4 (ниже).
А>>В будущем прямой доступ к буферу на запись может быть добавлен. Пока, проблему можно решить, введя дополнительный слой абстракции: A_A><код поскипан> А>>Настройками компиляции можно выбрать "законный" или быстрый вариант, не меняя код. A_A>А если в одном месте кода нужно быстро, а в другом месте безопасно?
Вряд ли есть проект, в котором один класс использует MSVC6 STL, а другой — STLport. В большинстве проектов весь код использует одну и ту же реализацию STL. То, как реализован string, и определяет выбор между GENERIC_STL_IMPL и REALISTIC_STL_IMPL. Вариант REALISTIC_STL_IMPL (без промежуточного буфера) вполне безопасный и работает со всеми известными мне реализациями STL.
A_A>Лучше использовать отдельный класс для манипуляций со строками.
Да. Создатели крупных библиотек (MFC, Qt, wxWidgets, VCL) так и делают. Часто их "велосипедные" строковые классы эффективнее стандартного.
А>>10.4. Конкатенация строк А>>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. A_A>То же самое, для критичного по производительности кода лучше использовать специализированный класс для манипуляций со строками.
Создатель библиотеки не может точно узнать, где критичный по скорости код (а string предназначался в первую очередь для библиотек, как стандартная инфраструктура). Если пользователь редко вызывает функцию, то она не критична по скорости. Но другой пользователь может вызывать ту же функцию очень часто, тогда она станет критичной по скорости. В таких условиях лучше попусту не терять эффективность из-за неудачно спроектированного string-а. Поэтому создатели крупных библиотек делают собственные строковые классы. Создатели библиотек поменьше (например, WTL) перенимают удачные решения.
А>>В функции DoConcat можно использовать класс ostringstream в качестве string builder-а. A_A>А вот это точно не стоит использовать в критичном по времени коде.
Допустим, я пишу переносимую библиотеку и мне нужно вернуть string из функции. Я знаю только два стандартных string builder-а:
Собственно, сам string.
ostringstream.
Разве есть ещё?
По поводу медленности iostreams согласен полностью.
А>>11. У priority_queue нет метода increase_priority(element) (чтобы ускорить выталкивание элемента из очереди). Поэтому priority_queue нельзя использовать в алгоритме Дейкстры и A*. Я не знаю, как устроена структура данных 'пирамида' (heap, частично упорядоченное сортирующее дерево), так что не могу сказать, можно ли безболезненно добавить increase_priority. A_A>Скорее всего, increase_priority придется сначала находить нужный элемент, удалять его и вставлять повторно с новым приоритетом.
Возможно, я хочу слишком много от priority_queue. Этот пункт можно вычеркнуть из "Проблем STL-контейнеров" (тем более что priority_queue — не контейнер, а всего лишь адаптер контейнера). В конце концов, есть Boost Graph Library, сделанная в STL-стиле.
Пётр Седов wrote:
> А>>3. Нет понятия 'NULL-итератор'. В качестве итератора, "ссылающегося в > никуда", обычно используют Container.end(). Но вместо кода:
А как имея интервал [begin, NULL), вместо [begin, end) обойти его в обратном направлении (итератор bidirectional)?
Или получить 3-ий с конца элемент (итератор random-access)? Или даже просто посчитать длину интервала (итератор
random-access)?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Шахтер, Вы писали:
Ш>У STL много минусов (про некоторые из них можно поискать на форуме), но главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального). Конкретные реализации тоже плохо эволюционируют и не в том направлении. Фактически мы имеем дело с мертвой вещью. Ближайший аналог -- MFC. Ш>Использовать мертвую вещь для новых проектов не стоит.
Из твоих размышлений неявно вытекает, что ты предлагаешь вообще не пользоваться промышленными и стандартизированными решениями... мда... комментарии излишни...
На MFC, кстати, реализовано _очень_ много ПО, и ничего, работает.
Ш>Что это за алгоритмы? А никто не знает -- произвол реализации. Хотя в том же Кнуте вагон алгоритмов сортировки. Ш>И библиотека, претендующая на стандартную должна не фиг знает что содержать, а чисто конкретно -- sort 2, sort 3, sort 4, ..., quick sort, merge sort, Ш>intro sort, quick random pivot sort и.т.д.
Ш>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. Причем совершенно непонятно, зачем такое ограничение. Никаких технических причин для этого нет. Сами контейнеры. Практически единственный мало-мальски полезный класс -- vector. А где списки? Я знаю много разных типов списков. Где они все? А где деревья? RB-tree AVL-tree B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
А никто и не ставил задачу реализовать набор примеров к книге Кнута.
Если очень надо, я думаю такие наборы примеров уже есть.
Если ты недавно прочитал Кнута и находишься под впечатлением от того, что там написано, то это не значит, что все должны бросится это реализовывать и использовать
Я думаю, я не сильно ошибусь, если скажу, что больше чем половине программистов в 90% случаев хватает возможностей, предоставляемых стандартной библиотекой С++. Если я гружу из БД пару десятков записей и помещаю в контейнер, то абсолютно всё равно в какой контейнер я их помещю и каким sort'ом я их буду сортировать, хоть sort 15, хоть sort 78. Производительности это не прибавит ни на йоту.
Ну в оставшихся случаях (когда не хватает возможностей библиотеки) программисту не поможешь, т.к. на все случаи жизни все равно контейнеры и алгоритмы не реализуешь.
Здравствуйте, Шахтер, Вы писали:
Ш>И аллокировать каждый объект в динамической памяти? Ш>Нет, спасибо.
А Вы любите хранить все на стеке? Было бы интересно посмотреть на стабильность такой программы (при условии, что это не Hello world). А "заряжать" многомегабайтные стеки для многопоточного приложения — это чревато, знаете ли. Память велика, но не безгранична.
Аноним wrote: > Ш>И аллокировать каждый объект в динамической памяти? > Ш>Нет, спасибо. > А Вы любите хранить все на стеке?
Я очень люблю — так как это очень быстро.
> Было бы интересно посмотреть на > стабильность такой программы (при условии, что это не Hello world). А > "заряжать" многомегабайтные стеки для многопоточного приложения — это > чревато, знаете ли. Память велика, но не безгранична.
Интересно посмотреть на программы с сотнями потоков.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Шахтер, Вы писали:
Ш>>И аллокировать каждый объект в динамической памяти? Ш>>Нет, спасибо.
А>А Вы любите хранить все на стеке? Было бы интересно посмотреть на стабильность такой программы (при условии, что это не Hello world). А "заряжать" многомегабайтные стеки для многопоточного приложения — это чревато, знаете ли. Память велика, но не безгранична.
Тут ты не прав. Если контейнер хранит свои элементы по значению, это ещё не значит, что всё это располагается на стеке.
Сравни:
shared_ptr<vector<some> >
и
vector<shared_ptr<some> >
В обоих случаях объекты some хранятся в "куче". При этом первый вариант имо даже предпочтительнее, т.к. на стеке занимается меньше памяти, да и вообще меньше памяти занимается, при этом контейнер хранит эл-ты по значению!
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>> Блин, а давайте ещё поспорим на тему "Какие недостатки у С++"
E>1) Очень сложный язык, очень гибкий, с нереально сложным синтаксисом. Это приводит к тому, что для коллективного программирования на C++ абсолютно необходима инструкция. E>А для написания хорошего компилятора нужен довольно большой НИИ
[skip]
E>Хватит?
Как сказал Страуструп:
There are only two kinds of languages: the ones people complain about and the ones nobody uses
Существует два типа языков: языки, которые все ругают, и языки, которые никто не использует
Имхо для языка бОльшая честь относится к первому типу, чем ко второму
Здравствуйте, IID, Вы писали:
S>>Мало квалифицированнах программистов, которые владеют STL. IID>Вы серъезно так думаете о С++ программистах ?
мало того, и сам C++ досконально тоже мало кто знает
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>мало того, и сам C++ досконально тоже мало кто знает
А это не возможно.
Потому что знание С++ завязано на знании интерпретации стандарта конкретным компилятором. Я работал с 5 компиляторами С++ (gcc, msvc, xlc, bc3.1, watcom c). Все они понимают С++ по-своему. Сам по себе язык не существует пока, к сожалению.
Удвой число ошибок, если не получается добиться цели.
R>Имхо для языка бОльшая чАсть относится к первому типу, чем ко второму
Это слишком грубая дихотомия.
На деле есть языки, которые используются до сих пор в своих областях, например FORTRAN. Он достаточно неплохо переносим (не 100%, конечно) и имеет неплохую защиту от дурака.
Удвой число ошибок, если не получается добиться цели.
Здравствуйте, IID, Вы писали:
IID>Здравствуйте, strcpy, Вы писали:
S>>Мало квалифицированнах программистов, которые владеют STL.
IID>Вы серъезно так думаете о С++ программистах ?
Смотря сколько денег предложить Если предложить определённую цифру в килобаксах, то можно ставить любые критерии, включая отличное знание стандартной библиотеки и boost. И люди, я уверен, найдутся.
Другое дело, что за одну и ту же среднестатистическую зарплату, на других языках можно найти гораздо более квалифицированных программистов, чем на с++. Это оследует хотя бы из того, что чтобы овладеть с++ профессионально надо гораздо больше времени.
И опять же другое дело, что многие конторы патологически душит жаба предлагать приличные зарплаты, и в тоже время они хотят именно с++ программистов. Результат понятен
довльно неудобно, что *std::map::iterator ссылается на std::pair<key, value>, а не на само value, в связи с этим очнь сложно использовать её со стандартными алгоритмами и биндом, благо в boost::ptr_map этого недостатка нет.
Здравствуйте, Kluev, Вы писали:
K> Если язык допускает отрицательный индекс для встроенного массива (которым в общем случае является указатель), значит контейнеры должны соотвествовать этому поведению
Язык не допускает операции с указателями, предшествующими началу массивов. Само получение таких указателей UB. Контейнеры соответствуют этому поведению.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, kan, Вы писали:
kan>Объясни, что является "обычным циклом" при обходе vector? а deque? а list? И почему я должен переписывать этот цикл, kan>если я вдруг поменял list на vector?
А зачем менять в программе list на vector?
И почему это должно быть легко сделать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>А зачем менять в программе list на vector? E>И почему это должно быть легко сделать?
Это не должно быть легко сделать. Скотт Мейджерс (надеюсь я не переврал имя автора) в своей книги пишет, что важно понимать, что у каждого контейнера — свои особенности поведения. Контейнеры, вообще говоря, не взаимозаменяемы, хотя иногда это и наблюдается.
Удвой число ошибок, если не получается добиться цели.
Здравствуйте, strcpy, Вы писали:
S>Это не должно быть легко сделать. Скотт Мейджерс (надеюсь я не переврал имя автора) в своей книги пишет, что важно понимать, что у каждого контейнера — свои особенности поведения. Контейнеры, вообще говоря, не взаимозаменяемы, хотя иногда это и наблюдается.
Тогда почему лёгкость замены в программе list на vector -- это довод в пользу итераторов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, kan_izh, Вы писали:
_>IROV.. wrote:
>> IID>for(int i=0; i!=array.size(); ++i)
>> Ты так на всякий случай загляни в std::vector<>::size(), и учти что это _>Ну так загляни: _>
Здравствуйте, Erop, Вы писали:
kan>>Объясни, что является "обычным циклом" при обходе vector? а deque? а list? И почему я должен переписывать этот цикл, kan>>если я вдруг поменял list на vector?
E>А зачем менять в программе list на vector? E>И почему это должно быть легко сделать?
У меня в проекте есть один алгоритм, который раньше был реализован вручную и широко использовал объединение множеств. Упорядоченность этих множеств была не важна, поэтому та реализация использовала list.
Позже алгоритм был переписан с использованием сторонней библиотеки. Но ту часть функциональности, которую библиотека не покрывает, всё равно пришлось делать вручную. Исторически сложившийся list остался на месте.
Буквально на днях я прикинул, что больше никакие специфические свойства list’а мне для этого алгоритма не нужны. Я внёс в программу два изменения. Первое — в typedef’е контейнера заменил слово list на vector. Второе — в то место, где этот контейнер заполнялся, добавил reserve(сколько надо).
Программа заработала сразу и дала прирост производительности в 10 миллисекунд на кадр входной видеопоследовательности.
Здравствуйте, Centaur, Вы писали:
kan>>>Объясни, что является "обычным циклом" при обходе vector? а deque? а list? И почему я должен переписывать этот цикл, kan>>>если я вдруг поменял list на vector?
E>>А зачем менять в программе list на vector?
<...> C>Буквально на днях я прикинул, что больше никакие специфические свойства list’а мне для этого алгоритма не нужны. Я внёс в программу два изменения. Первое — в typedef’е контейнера заменил слово list на vector. Второе — в то место, где этот контейнер заполнялся, добавил reserve(сколько надо).
C>Программа заработала сразу и дала прирост производительности в 10 миллисекунд на кадр входной видеопоследовательности.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, strcpy, Вы писали:
R>>Имхо для языка бОльшая чАсть относится к первому типу, чем ко второму S>Это слишком грубая дихотомия.
Он собственно это потом и добавил:
"There are only two kinds of languages: the ones people complain about and the ones nobody uses". Yes. Again, I very much doubt that the sentiment is original. Of course, all "there are only two" quotes have to be taken with a grain of salt.
S>На деле есть языки, которые используются до сих пор в своих областях, например FORTRAN. Он достаточно неплохо переносим (не 100%, конечно) и имеет неплохую защиту от дурака.
Ш>У STL много минусов (про некоторые из них можно поискать на форуме), но главный минус (из которого вытекают и все остальные) один -- эта библиотека перестала развиваться. По политическим соображениям STL включили в стандарт. Это привело к замораживанию интерфейса библиотеки (который далек от идеального). Конкретные реализации тоже плохо эволюционируют и не в том направлении. Фактически мы имеем дело с мертвой вещью. Ближайший аналог -- MFC. Ш>Использовать мертвую вещь для новых проектов не стоит. Ш>Теперь более конкретно.
Ш>1) STL это библиотека алгоритмов и контейнеров. Ш>2) Какие алгоритмы есть в этой библиотеке? Из серьёзных и востребованых -- sort, stable_sort, heap_sort . Всё остальное -- не алгоритмы, а мелкие утилиты, в большинстве бесполезные (типа знаменитого for_each).
Ш>sort, stable_sort
Ш>Что это за алгоритмы? А никто не знает -- произвол реализации. Хотя в том же Кнуте вагон алгоритмов сортировки. Ш>И библиотека, претендующая на стандартную должна не фиг знает что содержать, а чисто конкретно -- sort 2, sort 3, sort 4, ..., quick sort, merge sort, Ш>intro sort, quick random pivot sort и.т.д.
Ш>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. Причем совершенно непонятно, зачем такое ограничение. Никаких технических причин для этого нет. Сами контейнеры. Практически единственный мало-мальски полезный класс -- vector. А где списки? Я знаю много разных типов списков. Где они все? А где деревья? RB-tree AVL-tree B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило.
Ш>Короче. Диагноз -- халтура. Два балла.
Извини, товарищ, если я не прав, но кажется мне, что ты стонешь по полноценному фреймворку. С++ и без STL как язык мощнее многих других, и STL дополняет его мощь ну не знаю на сколько процентов...
Re[3]: минусы STL
От:
Аноним
Дата:
17.09.06 18:52
Оценка:
Я не критикую твой пост, меня и самого STL многим не устраивает, но все же я рад, что она включена в стандарт, и не буду говорить про то, что самого бы посадить в Комитет, и запел бы там, обсуждая, стандартизовывая, etc. Может посмотреть на это дело с бОльшей высоты...
Здравствуйте, strcpy, Вы писали:
R>>Имхо для языка бОльшая чАсть относится к первому типу, чем ко второму S>Это слишком грубая дихотомия. S>На деле есть языки, которые используются до сих пор в своих областях, например FORTRAN. Он достаточно неплохо переносим (не 100%, конечно) и имеет неплохую защиту от дурака.
фортран имеет защиту от дурака?
вот здесь поподробнее, какую конкретно?
IROV.. wrote:
> тебя устраивает каждый такт цыкла вызывать _лишний_ оператор сравнения?
Тесты в студию.
>> > будет вызыватся каждый такт цыкла. > _> > For many containers, such as vector and deque, size is O(1) > _>Это тебе не strlen. Так что мимо тазика. > O(1) бывает разным > зачем платить больше?
Есть такая штука — premature optimization.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan, Вы писали:
kan>Пётр Седов wrote:
>> А>>3. NULL-итераторы kan>А как имея интервал [begin, NULL), вместо [begin, end) обойти его в обратном направлении (итератор bidirectional)? Или получить 3-ий с конца элемент (итератор random-access)? Или даже просто посчитать длину интервала (итератор random-access)?
Всё как обычно, я не против end-итератора. NULL-итератор — это не терминатор последовательности (как завершающий '\0' в C-строках). NULL-итератор нужен, чтобы ссылаться "в никуда". Здесь
Здравствуйте, night beast, Вы писали:
NB>фортран имеет защиту от дурака? NB>вот здесь поподробнее, какую конкретно?
Я не знаю что имел в виду автор высказывания, но на фортране однозначно дурак программировать не затянет
Хотя я фортарн люблю, если для вычматов, конечно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Пётр Седов wrote:
>> > А>>3. NULL-итераторы > kan>А как имея интервал [begin, NULL), вместо [begin, end) обойти его в > обратном направлении (итератор bidirectional)? Или получить 3-ий с конца > элемент (итератор random-access)? Или даже просто посчитать длину > интервала (итератор random-access)? > Всё как обычно, я не против end-итератора. NULL-итератор — это не > терминатор последовательности (как завершающий '\0' в C-строках). > NULL-итератор нужен, чтобы ссылаться "в никуда". Здесь
Так а чем тогда "неициализированный" итератор не устраивает?
std::vector<Type>::iterator nullIterator;
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Erop, Вы писали:
NB>>фортран имеет защиту от дурака? NB>>вот здесь поподробнее, какую конкретно?
E>Я не знаю что имел в виду автор высказывания, но на фортране однозначно дурак программировать не затянет
это точно
как-то разбирался с одним алгоритмом.
с фортрановскими вычисляемыми джампами, вот уж где без дебегера никак. было весело.
но то что серьезного конроля типов там нет, это факт.
E>Хотя я фортарн люблю, если для вычматов, конечно
Здравствуйте, night beast, Вы писали:
NB>но то что серьезного конроля типов там нет, это факт.
Нахрена он в вычматах?
E>>Хотя я фортарн люблю, если для вычматов, конечно NB>давно это было
Мне пока что пригождается время от времени
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, night beast, Вы писали:
NB>>>но то что серьезного конроля типов там нет, это факт. E>>Нахрена он в вычматах?
NB>от дураков защищаться
Да там типы всё время одни и теже. Столбец чисел, да матрица чисел. Так что контролируй типы не контролируй а толку никакого
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ghostrider, Вы писали:
G>1) Контейнеры STL не транзакционны. Т.е. если во время операции с контейнером не удалось выделить память, то после этого контейнер находится в неопределнном состоянии — уже не исходное, но еще не конечное. Соответственно типы, которые хранят данные в STL контейнерах тоже не будут транзакционными, если не прилагать специальных усилий и терять при этом эффективность. G>2) В случае невозможности выделения памяти контейнеры STL кидают исключение. Стало быть, вызывающий код обязан его обрабатывать. Если вы используете STL в программе, это не так страшно, а вот если пишете библиотеку ф-ций с использованием STL, то тем самым навязываете пользователю то, что он тоже должен обрабатывать исключения. Если Вы используете контейнеры только внутренне и аккуратно обрабатываете все исключения, то тогда еще не все потеряно. А вот если используете типы STL в параметрах ф-ций, тогда плохо дело.
О безопасности контейнеров
В STL фактически существует только одна функция-метод, о которой в стандарте явным образом сказано, что она должна генерировать исключение [1-23.1/13]. Речь идет о функции at(), реализующей надежный доступ к элементу вектора или дека. Функция должна генерировать стандартное исключение out_of_range, если аргумент превышает size(). В остальных случаях стандарт требует лишь стандартных исключений вроде bad_alloc при нехватке памяти, или исключений, возникающих при пользовательских операциях. Стандартная библиотека обеспечивает базовую гарантию безопасности исключений: возникновение исключений в стандартной библиотеке не приводит к утечке ресурсов и нарушению контейнерных инвариантов. Более того, многие операции с контейнерами либо вовсе не генерируют исключений, либо обеспечивают транзакционную безопасность: если во время выполнения операции возникнет исключение, то произойдет откат — возврат к состоянию контейнера до начала выполнения операции.
Большинство операций с контейнерами в отношении надежности выполнения можно разделить на 4 класса:
не генерирует исключений;
либо завершается успешно, либо не вносит изменений;
не генерирует исключений, если они не генерируются при копировании или присваивании элементов (аналогично — при сравнении);
либо завершается успешно, либо не вносит изменений, если при копировании или присваивании не генерируется исключений.
Таким образом, если пользователь будет аккуратно программировать свои классы, уделяя внимание проблемам возникновения исключений, то стандартная библиотека практически гарантирует безопасность обработки элементов в контейнере.
Если с точки зрения безопасности рассматривать контейнеры, то библиотека гарантирует две вещи:
1. для списка, множества (мультимножества), отображения (мультиотображения) гарантируется транзакционная безопасность: удаление элемента никогда не завершается неудачей; неудачная попытка вставки оставляет контейнер в прежнем состоянии;
2. для вектора и дека гарантируется транзакционная безопасность операций на концах контейнера; если конструктор копирования и операция присваивания элемента не генерируют исключений, то любые операции с этими элементами либо завершаются успешно, либо не вносят изменений.
Множество и отображения гарантируют только одноэлементную транзакционную безопасность вставки (то есть, либо завершается успешно, либо не вносит изменений), а вот список обеспечивает откат неудачной вставки нескольких элементов. Более того, любые операции (кроме remove(), remove_if(), sort(), merge() и unique()) либо выполняются успешно, либо не вносят изменений. Таким образом, если вам требуется надежный контейнер, используйте список.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
NB>>но то что серьезного конроля типов там нет, это факт. E>Нахрена он в вычматах?
Фортран, как стандарт, хорошо автоматически распаралеливается некоторыми кластерными системами.
В С++ же приходится делать unroll циклов.
Удвой число ошибок, если не получается добиться цели.
Здравствуйте, Шахтер, Вы писали: Ш>>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы. Это огромный минус. _>>это элементарно обходится: используй контейнеры на SmartPtr, а сам указатель может быть и некопирабельным. Ш>И аллокировать каждый объект в динамической памяти? Ш>Нет, спасибо.
Покажите мне массив, который может увеличивать свой размер, не требующий памяти их хипа. Я хочу ЭТО увидеть
Здравствуйте, Erop, Вы писали: E>>>Имеются в виду автоматические тесты готового изделия? И при этом ещё подразумевается воссоздание всех разнообразных условий компиляции и версий STL ? _>>всех это уже маразм _>>обычно ищетсяя компромис E>всех -- это всех встречающихся у пользователей
На скольких типах процессоров\матерей Вы свою программу тестировали?
>>> kan> А что означает "i < vec.size() — 1", особенно в случае нулевого >>> размера? >>> Означает итерировать все кроме последнего. Читается точно так же как и >>> думается.
написанное выражение данному условию не удовлетворяет
K>Фраза итерировать все кроме последнего сотоит из двух частей. K>1) итерировать все K>2) кроме последнего
тогда пиши так ( !vec.empty() && i < vec.size()-1 )
Здравствуйте, Cyberax, Вы писали:
C>Шахтер wrote: >> Где они все? А где деревья? RB-tree AVL-tree >> B-tree ? Похоже, авторам так и не удалось прочитать Кнута. IQ не хватило. C>В Boost'е А еще в STL из полезных вещей есть map, string. В принципе, C>больше особо ничего и не использую оттуда.
string? и map?
По моему вообще самые неудобоваримые штуки.
string там должен быть или COW и/или дополнен slice (immutable fragment). Про набор методов я вообще промолчу.
А map? Как хранилище key/value пар? Ну дык hashmap эффективнее.
Или как упорядоченный по ключу набор? И часто такое нужно?
>> Короче. Диагноз -- халтура. Два балла. C>Вполне нормальная библиотека, ее достоинство в том, что она продвинула в C>массу идею разделения алгоритмов и контейнеров.
Это точно нужно. Для написания абстрактных алгоритмов выпаса сферических коней в виртуальных
континуумах.
В том смысле что далеко не всем выпадает счастье приобщиться к роскоши написания некоего общего алгоритма
для класса контейнеров. Как правило есть контейнер строго определенный и алгоритм один единственный — самый оптимальный.
И времени ёк на то чтобы писать вселенскую абстракцию в стиле stl. Имхо stl уж слишком абстрактно далек от реальных задач.
2 Пётр Седов
Это стеки не в моей программе а от нее в дисассемблере вниз
2 c-smile >C>массу идею разделения алгоритмов и контейнеров.
Ну я когдато контейнеры на BC читал — сейчас глянул вроде мухи от котлет отдельно. Кажется тогда можно было динамически подсовывать контейне — так далеко абстракции вели. Тоесть во время исполнения хош лист хош вектор.
Здравствуйте, strcpy, Вы писали:
S>Мало квалифицированнах программистов, которые владеют STL. S>Поэтому код на STL рискует стать трудносопровождаемым.
Если Вы имеете в виду программистов Java или VB, то да — они редко знают STL.
А программист C++, который не владеет STL не должен называться квалифицированным.
А теперь немного об STL
"Any road followed precisely to it's end leads precisely nowhere"
Dune, Bene Gesserit saying
Не так давно я узнал, когда именно г-ну Степанову пришла идея библиотеки STL — когда он находился в отделении интенсивной терапии (после отравления рыбой) в, как он сам написал, "delirium state", по-просту — в состоянии БРЕДА.
Этот малеьнкий фактик очень удачно вписался в мои собственные представления об STL и самом языка С++. В предельно короткой форме: STL — это просто болезненный бред.
Бред относится к авторам библиотеки, а болезненный — это состояние ее пользователей.
Уже с самого начала STL производит впечатление чего-то монстроидального и совершенно непонятного. Это нагромождение template'd классов (яязык не поворачивается называть их объектами, это просто АТД-переростки) с огромным количество параметров и морем методов с весьма непонятными названиями.
.................................
Здравствуйте, Slava Antonov, Вы писали: SA>А есть какие то более аргументированные факты?
сложность, неэфективность — выше писал.
Еще негибкость — немогу array абстрактного класса сделать. Вон траблы на соседей ветке
Здравствуйте, Programador, Вы писали:
P>Ну я когдато контейнеры на BC читал — сейчас глянул вроде мухи от котлет отдельно. Кажется тогда можно было динамически подсовывать контейне — так далеко абстракции вели. Тоесть во время исполнения хош лист хош вектор.
Слышь, Тореро, я извиняюсь, это на каком языке всё написано?
Здравствуйте, remark, Вы писали: R>Я думаю, я не сильно ошибусь, если скажу, что больше чем половине программистов в 90% случаев хватает возможностей, предоставляемых стандартной библиотекой С++. Если я гружу из БД пару десятков записей и помещаю в контейнер, то абсолютно всё равно в какой контейнер я их помещю и каким sort'ом я их буду сортировать, хоть sort 15, хоть sort 78. Производительности это не прибавит ни на йоту. R>Ну в оставшихся случаях (когда не хватает возможностей библиотеки) программисту не поможешь, т.к. на все случаи жизни все равно контейнеры и алгоритмы не реализуешь.
Мы сейчас активно используем Python. Одна из прелестей — очень большая библиотека в стандартной поставке:
Строки разбираешь — регекспы есть.
Работа с уникодом и кодировками — да.
HTML/XML — парсеры входят.
Многопоточность — ага.
Операции с операционной системой — конечно.
Сокеты — пожайлуста.
Протоколы над сокетами — все распространенные.
Работа с архивами — zlib, tar, gzip, bzip, zip
Простые базы данных — dumbdbm, dbm, gdbm, беркли
Реляшки — sqlite и стандарт на драйвера.
GUI — TkInter
Даже отладчик и профилер — штатныйе.
Получаються несколько отличные структуры разработки:
На Python-е написал реализацию, тотом смотришь, если где-то стандартный компонент не подходит по каким-то критериям, ищешь замену (или переписываешь).
В эхотаге — ищешь требуемые компаненты (или пишешь сам) — потом пишешь реализацию, в случае, если что-то подходит ищешь замену (или переписываешь).
Т.е. как минимум на один шаг больше.
Кроме того, на первом шаге для эхотага не известны критерии.
К тому же т.к. в python-е очень многое есть в поставке, альтернативы довольно похожи по интерфейсу.
По моему STL-ем пытались решить именно эту проблему.
Сейчас её же пытается решить BOOST...
Здравствуйте, c-smile, Вы писали:
CS> Про набор методов (std::string) я вообще промолчу.
Посмотрите например в MS реализации — size() занимает O(1). Так вот как вы сделаете это без запихивания всех методов внутрь объекта? КАК? Приведите эту реализацию, а мы поглумимся — наверняка какие-нибудь кривости будут. Александреску умен, но у него свои тараканы, нечего их себе в голову пересаживать — не надо написанному верить как истине в последней инстанции. Что-то бесспорно хорошо, а что-то... Кхм, наверно он книгу после работы писал, че не напишешь после 8+ часов перед монитором То что все методы внутри позволяют реализовать size(), end() эффективно — за O(1).
Не стыдно попасть в дерьмо, стыдно в нём остаться!
Здравствуйте, ., Вы писали:
>> В предельно короткой форме: STL — это просто болезненный бред. .>Надо чуваку boost показать. Тогда он убъёт себя о стенку.
Да ладно, boost -- это уже бред не болезненный, а сладострастный. Это когда боль превышает какой-то порог, она начинает приносить практически наркотическое удовольствие
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
а ты с чем не согласен-то?
с тем, что STL навязывается или с трудностями тестирорвания?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
невозможность привязки итераторов к виджетам
т.е. если у меня есть например stl-список в памяти и экранный список в диалоге, нет никакой возможности запихнуть итераторы в 32-битные поля SetItemData, передать через lParam и т.д.
по возможности пользуюсь аналогичными классами MFC, в которых вместо итераторов есть замаечательный тип POSITION
для кроссплатформенных проектов думаю выдрать afxtempl их MFC и сделать свою маленькую библиотеку контейнеров (а заодно немного расширить контейнеры MFC).
еще общие соображения: STL слишком крут для С++. В самом языке нет тех возможностей, чтобы библиотеки типа STL выглядели более дружественно. Отсюда все эти шаблонные навороты. Такие фундаментальные концепции как "контейнер", "итератор" и "алгоритм" стоит реализовывать на уровне самих языков, а не городить огороды с шаблонами.
Здравствуйте, x-code, Вы писали:
XC>еще общие соображения: STL слишком крут для С++. В самом языке нет тех возможностей, чтобы библиотеки типа STL выглядели более дружественно. Отсюда все эти шаблонные навороты. Такие фундаментальные концепции как "контейнер", "итератор" и "алгоритм" стоит реализовывать на уровне самих языков, а не городить огороды с шаблонами.
Да там главная мулька -- это бесконечная расширяемость STL.
На практике, же попытка воспользоваться этой мулткой -- признак чистейшего и незамутнённого безумия. ИМХО, разумеется
А вообще идея продумать и написать небольшую юиюлиотеку, в которой будут
массивы, списки, деревья и простые умные указатели
Хэши и хэшмэпы (а не то прекрасное изделие, которое есть в stl под названием map)
стредства управления памятью
средства доступа к бинарным файлам
средства сериализации в текст (хотя против потоков я как раз ничего не имею, просто хочется, чтобы всё совместимо осталось)
средства сереализации в бинарный архив
система исключений
строчки.
И типа более или менее всё -- она позитивная весьма.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, LuciferMoscow, Вы писали:
E>>всех -- это всех встречающихся у пользователей LM>На скольких типах процессоров\матерей Вы свою программу тестировали?
Сотнях.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Roman Odaisky, Вы писали:
RO>Предлагаю реализовать аналог std::deque без итераторов.
А в чём проблема?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tonal-, Вы писали:
T>По моему STL-ем пытались решить именно эту проблему. T>Сейчас её же пытается решить BOOST...
ИМХО, причина в некоторой консервативности комитета. Примерная цитата из "Дизайн и эволюция С++"(о принятие очереднрого стандарта)
В некоторый момент мы были вынуждены остановить прием новых заявок(на изменение\дополнение), т.к. уже внесенных(но нерасмотренных) предложений было очень много. И не сделай мы этого стандарт никогда бы не вышел, т.к. скорость поступления заявок превышал скорость их рассмотрения
Здравствуйте, Tonal-, Вы писали:
T>Здравствуйте, LuciferMoscow, Вы писали: LM>>Покажите мне массив, который может увеличивать свой размер, не требующий памяти их хипа. Я хочу ЭТО увидеть
Здравствуйте, Smal, Вы писали:
S>Ну, а те, кого не интересует мнения классиков, обречены вечно наступать на свои же грабли. S>Ибо, как известно, дурак учится на своих ошибках, а умный на чужих %).
S>К сожалению, такой порядок дел не изменить в силу все той же закостенелости мышления и нежелании что-либо менять. S>Поэтому, ИМХО, данная ветка уже давно перешла в ранг холиворов вроде C vs C++.
S>Остается только надеяться, что такое положение дел положительно скажется на развитии стандартной библиотеки.
Не знаю. Вот, например, никто мне так и не объяснил зачем нужны алгоритмы? Вот все эти count_if и foreach и merge?
Особенно хотелось бы понять, зачем нужен merge. В смысле почему нигде кроме stl нет такой *сверхнужной* фичи в стандартной библиотеке?
Насколько я понимаю в STL есть две великие идеи.
1) STL бесконечно расширяем. Туда можно дописывать новые контейнеры, алгоритмы, примитивы и всё будет совершенно монолитно и бесшовно интегрировано с STL. В этом смысле претензия, что типа нету B-деревьев, несостоятельная. Надо добавить B-деревья просто и всё.
2) Он совместим в смысле совместимости C++. То есть есть набор всяких соглашений и гарантий, которые будут выполняться любой реализацией и на любой платформе. Это конечно тоже очень круто и прикольно сделано
Ну и есть ещё одна тонкость -- STL ещё и довольно эффективен, и типобезопасен при этом.
Это всё конечно плюсы. Минусы же такие, что STL не только тяжек в применении к реальным задачам, но ещё и переусложнён
То есть, как это ни странно, расширяемость STL, ИМХО, вообще не нужная фича. Алгоритмы -- тоже очень ограниченно полезная.
Совместимость STL на поверку оказывается фикцией, так как он очень сложный и код, его использующий, тоже сложный, а ошибки на каждой комбинации платформы и версии STL проявляются свои
Ну а эффективность STL она не благадаря этакой его кудрявости, всё-таки, а скорее вопреки.
Вот собственно поэтому некоторым людям STL и не нравится.
Конечно если у тебя нет никакой друго библиотеки примитивов и контейнеров, то надо использовать STL, чем писать просто на голом C++.
Но если вдруг есть, или есть ресурсы, для разработки такой библиотеки, то, ИМХО, лучше пользоваться своей простой и понятной и эффективной и расширяемой конструкцией.
То есть получается немного парадоксально. Если у вас большой-пребольшой проект и контора, то вам конечно мог бы пригодиться прекрасный мощный и универсальный stl, но намного лучше вам подойдёт что-нибудь более простое и более по месту.
А если у вас короткий, компактный, дешёвый проект, то вам вся мощь STL только мешает
Просто в STL так много всяких кустов и деревьев, что за ними виден прекрасный и полезный "лес", только на довольно большом проекте. А там, как раз, без него ещё лучше всё выходит.
Ну а если вдруг таки у вас проект попроще, то сверхсложные синтаксические кусты просто закроют от вас лес и ничего вы позитивного не увидите.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
S>>Не надо далеко ходить... Нет способа преобразовать число в std::string и обратно. Так, чтобы было одновременно быстро, удобно и безопасно.
_>вот интерестно где есть такое? и чтоб всем трём одновременно условиям удовлетворяло?
Ну PowerPlant, например, тебя устроит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>Каждый раз натыкаюсь, и каждый раз матерюсь. ШЕ>Бывает надо написать обощённый класс, который возвращает ссылку на тип, ШЕ>а контейнер там vector и надо вдруг bool использовать...
ШЕ>... и начинаются подпорки ввиде специализаций и замены ШЕ>внутреннего типа на какой-нибудь char
Здравствуйте, LuciferMoscow, Вы писали: T>>Здравствуйте, LuciferMoscow, Вы писали: LM>>>Покажите мне массив, который может увеличивать свой размер, не требующий памяти их хипа. Я хочу ЭТО увидеть
<skipped> T>>g++ (GCC) 3.4.5 (mingw special) LM>
А если серьёзно, то это расширение gcc всего лишь синтаксическая надстройка над alloca+placement new.
Сочинить собственный велосипед в эту тему — тривиально.
Здравствуйте, Tonal-, Вы писали:
LM>>>>Покажите мне массив, который может увеличивать свой размер, не требующий памяти их хипа. Я хочу ЭТО увидеть T>>>g++ (GCC) 3.4.5 (mingw special) LM>>
T>Ты где-то просил чтобы решение было переносимо?
Это подразумевалось, т.к. мы говорим об STL. А как добавлять элементы в Ваш массив?
T>А если серьёзно, то это расширение gcc всего лишь синтаксическая надстройка над alloca+placement new. T>Сочинить собственный велосипед в эту тему — тривиально.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[3]: Возвращаясь к украинской теме: Сколько же точек над i
Здравствуйте, Erop, Вы писали:
E>Это всё конечно плюсы. Минусы же такие, что STL не только тяжек в применении к реальным задачам, но ещё и переусложнён E>То есть, как это ни странно, расширяемость STL, ИМХО, вообще не нужная фича. Алгоритмы -- тоже очень ограниченно полезная. E>Совместимость STL на поверку оказывается фикцией, так как он очень сложный и код, его использующий, тоже сложный, а ошибки на каждой комбинации платформы и версии STL проявляются свои
E>Ну а эффективность STL она не благадаря этакой его кудрявости, всё-таки, а скорее вопреки.
Почему???
E>Конечно если у тебя нет никакой друго библиотеки примитивов и контейнеров, то надо использовать STL, чем писать просто на голом C++. E>Но если вдруг есть, или есть ресурсы, для разработки такой библиотеки, то, ИМХО, лучше пользоваться своей простой и понятной и эффективной и расширяемой конструкцией.
E>А если у вас короткий, компактный, дешёвый проект, то вам вся мощь STL только мешает E>Просто в STL так много всяких кустов и деревьев, что за ними виден прекрасный и полезный "лес", только на довольно большом проекте. А там, как раз, без него ещё лучше всё выходит. E>Ну а если вдруг таки у вас проект попроще, то сверхсложные синтаксические кусты просто закроют от вас лес и ничего вы позитивного не увидите.
Ты не поверишь, наверное, но я во всех своих мелких проектах (включая те, которые я делаю дома для себя, просто чтоб сделать какую-нть мелкую фигню) использую STL и ну вообще никаких проблем с ним не испытываю. А уж тем более в комбинации с boost. И "вся его мощь" мне только помогает
Здравствуйте, LaptevVV, Вы писали:
LVV>Подчеркивание того, что множество — ассоциативный контейнер — только с толку сбивает начинающего...
Действительно, начинающему куда как понятнее, как написать хорошую хэш-функцию
LVV>Множество — это множество, как бы оно ни было реализовано... LVV>Подчеркивать специфику реализации не стоило и для map — можно было б и как хеш реализовать...
Не понял. Ты как собираешься уникальность ключей гарантировать? Вот что бы ты не ответил, я тебе на это скажу: это и является спецификой предлагаемой тобой реализации, это и есть те самые "уши". Если через operator== — все типы должны подерижвать его. Если через hash_func — то же самое. Если через std::less или явный предикат (как в STL) — то же самое.
Выбор STL в далеко не самый плохой, потому что через operator== я вообще не представляю, как можно гарантировать что-либо, кроме уникальности (например, скорость поиска). Написание хорошей хэш-функции — задача далеко не тривиальная. Можешь в качестве упражнения написать хорошую хэш-функцию для int. А в STL мы имеем, в первую очередь, очень большую гибкость благодаря тому, что мы можем понимать эквивалентность ключей как нам заблагорассудится, даже для одного и того же типа; во-вторых, мы имеем вполне хорошую скорость поиска (логарифмическую); в-третьих, мы абсолютно на халяву получаем возможность доступа к контейнеру как к сортированной по нашему вкусу последовательности, что является крайне часто встречающейся задачей.
Так что в качестве универсального решения, которое подойдет на все случаи жизни, кроме особо критичных по скорости (когда имеет смысл использовать хэш), STL очень даже хороша.
Опять же, у хэшей своих проблем хватает, и без понимания того, как хэш будет работать в твоем _конкретном_ случае (т.е. на конкретных ожидаемых тобой данных), вообще лучше в хэш не соваться. Ты-то должен понимать, что "просто хэша" не бывает: чтобы быть эффективным, он должен быть заточен под конкретные условия использования.
LVV>А набор алгоритмов — это вообще напорминает свалку...
А конкретнее? Что ты предлагаешь?
LVV>И похоже на то, что новой редакции STL мы не скоро дождемся... Тока вместе со стандартом...
Естественно, потому что STL (т.е. библиотеки фирмы SGI) — такой штуки не существует в контексте данного обсуждения, а существует стандартная библиотека С++, которая, естественно, является частью стандарта С++.
d, i целое со знаком
U беззнаковое целое
O беззнаковое восьмеричное целое
x, X беззнаковое шестнадцатеричное целое
l, h "длинное" или "короткое" целое (префиксы, используемые совместно с символами d, i, u, o, x, X)
F вещественное число со знаком
E вещественное число со знаком в научной нотации
G вещественное число со знаком (нотация выбирается автоматически)
C cимвол
S строка в кодировке ANSI
Su строка в кодировке Unicode
St строка в кодировке ANSI или Unicode
Hr HRESULT или код ошибки Win32
Wc флаг класса окна
Wm код сообщения
<число> количество элементов массива
Дело в том что последний работает только для указателей в отличии от Борланда, поэтому мне раньше казалось что его нет.
И возможен доступ к вектору из отладчика по внятным именам dv._First,9 и такое dv._Last-dv._First . У Борланда этого не было. Кроме того VC6 сложные инлайны инлайнит до 256-уровня (регулируется) вложенности.
XC>невозможность привязки итераторов к виджетам XC>т.е. если у меня есть например stl-список в памяти и экранный список в диалоге, нет никакой возможности запихнуть итераторы в 32-битные поля SetItemData, передать через lParam и т.д. XC>по возможности пользуюсь аналогичными классами MFC, в которых вместо итераторов есть замаечательный тип POSITION XC>для кроссплатформенных проектов думаю выдрать afxtempl их MFC и сделать свою маленькую библиотеку контейнеров (а заодно немного расширить контейнеры MFC).
как мне кажется тут проблема у MFC... т.к. выделенное это С стиль
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>как мне кажется тут проблема у MFC... т.к. выделенное это С стиль
Ну так и винда и Х-винда и интерфейсы на всяких телефонах-контроллерах-кофеварках они все C-стиль
Как-то реальные задачи хочется программировать в реальных системах а не в последовательных С++-системах будущего
Тем более, что вдруг оно не наступит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
XC>>невозможность привязки итераторов к виджетам XC>>т.е. если у меня есть например stl-список в памяти и экранный список в диалоге, нет никакой возможности запихнуть итераторы в 32-битные поля SetItemData, передать через lParam и т.д. XC>>по возможности пользуюсь аналогичными классами MFC, в которых вместо итераторов есть замаечательный тип POSITION XC>>для кроссплатформенных проектов думаю выдрать afxtempl их MFC и сделать свою маленькую библиотеку контейнеров (а заодно немного расширить контейнеры MFC).
_>как мне кажется тут проблема у MFC... т.к. выделенное это С стиль
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, gid_vvp, Вы писали:
E>>>Ну PowerPlant, например, тебя устроит?
_>>не знаю _>>а что это?
E> Коммерческая библиотека классов, которая поставляется, например, с CodeWarrior
LuciferMoscow wrote:
> Это подразумевалось, т.к. мы говорим об STL. А как добавлять элементы в > Ваш массив?
Написать свой аллокатор, который будет использовать alloca.
Правда нафиг нужно — непонятно.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Написать свой аллокатор, который будет использовать alloca. .>Правда нафиг нужно — непонятно.
Зачем не знаю. Но мне так кажется, что выделенное осуществить не удастся
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop wrote:
> .>*Написать свой аллокатор, который будет использовать alloca.* > .>Правда нафиг нужно — непонятно. > Зачем не знаю. Но мне так кажется, что выделенное осуществить не удастся
Почему? Аллоцировать с запасом, деаллокация — ничего не делает (или отмечает блок как свободный, на случай если кто-то
другой запросит блок такого размера), аллокация — всегда выделяет новый буфер.
Правда всё равно в реальной жизни это бесполезно, т.к. размер стека жутко ограничен.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, gid_vvp, Вы писали:
E>> Коммерческая библиотека классов, которая поставляется, например, с CodeWarrior
_>а её можно посмотреть не покупая?
Не знаю. У меня когда-то получалось
Может потому, что я это делал под MacOS, там есть своя специфика с пиратством
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, gid_vvp, Вы писали:
E>>> Коммерческая библиотека классов, которая поставляется, например, с CodeWarrior
_>>а её можно посмотреть не покупая? E>Не знаю. У меня когда-то получалось E>Может потому, что я это делал под MacOS, там есть своя специфика с пиратством
Здравствуйте, gid_vvp, Вы писали:
_>я полагаю использовать GUI библиотеки написанные в С++ стиле
Библиотека называется Windows API или X-Windows, например.
О сотовых телефонах я вообще скромно молчу пока что.
И? Как решаем?: )
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, gid_vvp, Вы писали:
_>>я полагаю использовать GUI библиотеки написанные в С++ стиле E>Библиотека называется Windows API или X-Windows, например. E>О сотовых телефонах я вообще скромно молчу пока что. E>И? Как решаем?: )
Здравствуйте, ., Вы писали:
>> Это подразумевалось, т.к. мы говорим об STL. А как добавлять элементы в >> Ваш массив? .>Написать свой аллокатор, который будет использовать alloca. .>Правда нафиг нужно — непонятно.
Т.е. Вы из стека кучу собираетесь сделать?
Здравствуйте, ., Вы писали:
.>Почему? Аллоцировать с запасом, деаллокация — ничего не делает (или отмечает блок как свободный, на случай если кто-то .>другой запросит блок такого размера), аллокация — всегда выделяет новый буфер.
Потому, что alloca выделяет память на стековом фрейме вызывающей функции, то есть метода аллокатора
Так как inline-подсьановку метода гарантировать невозможно, то и работтоспособность этого "изделия" гарантировать не удастся
.>Правда всё равно в реальной жизни это бесполезно, т.к. размер стека жутко ограничен.
Странно. В известных мне операционках, обычно можно отматать столько стэка, сколько надо...
Пишешь нужное число в заголовок exeшника и всё...
А ещё можно стэк другой нити использовать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop wrote:
> .>Почему? Аллоцировать с запасом, деаллокация — ничего не делает (или > отмечает блок как свободный, на случай если кто-то > .>другой запросит блок такого размера), аллокация — всегда выделяет > новый буфер. > Потому, что alloca выделяет память на стековом фрейме вызывающей > функции, то есть метода аллокатора
Хм... Действительно... Не подумал. Если можно как-то параметром аллокатору передавать текущий стековый фрейм... В
общем тут я уже сомневаюсь.
> .>Правда всё равно в реальной жизни это бесполезно, т.к. размер стека > жутко ограничен. > Странно. В известных мне операционках, обычно можно отматать столько > стэка, сколько надо...
По умолчанию 1 мег. А как стек можно мотать динамически? Как оно будет гарантировать то, что место будет?
> Пишешь нужное число в заголовок exeшника и всё...
Ну это аналогично вызову reserve с большим числом прозапас (или специальному аллокатору с фиксированным размером).
> А ещё можно стэк другой нити использовать...
Извращенец.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, gid_vvp, Вы писали:
_>да хотябы примеры доки... чтоб оценить
Если найду -- кину.
Там идея такая, что можно преобразовывать строки в числа и взад. Довольно легко и прямо.
При этом они там строки короче чего-то вообще не аллокируют никогда.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>пишем C++ обёртки над этим C style API
Ну это и есть так называемое "совсем не уменьшается производительность труда" и "зачем писать свой велосипед, если есть STL"
Но это всё лирика. Вот есть LISTBOX. Наверное он довольно известен. На всяк случай скажу, что там на элемент можно задать 32 бита данных.
И что же мы пишем, чтобы запихнуть туда итератор?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>Хм... Действительно... Не подумал. Если можно как-то параметром аллокатору передавать текущий стековый фрейм... В .>общем тут я уже сомневаюсь.
И не зря
>> Странно. В известных мне операционках, обычно можно отматать столько >> стэка, сколько надо... .>По умолчанию 1 мег. А как стек можно мотать динамически? Как оно будет гарантировать то, что место будет?
Ну заранее в заголовке EXE пишешь максимальный размер, какой тебе надо и пользуйся, хоть ГИГ
>> А ещё можно стэк другой нити использовать... .>Извращенец.
А то!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, gid_vvp, Вы писали:
_>>да хотябы примеры доки... чтоб оценить E>Если найду -- кину. E>Там идея такая, что можно преобразовывать строки в числа и взад. Довольно легко и прямо.
boost::lexical_cast E>При этом они там строки короче чего-то вообще не аллокируют никогда.
MS реализация std::string
Здравствуйте, c-smile, Вы писали:
CS>А map? Как хранилище key/value пар? Ну дык hashmap эффективнее. CS>Или как упорядоченный по ключу набор? И часто такое нужно?
Бывает нужно, и не так уж редко. А вот написать хорошую хэш-функцию, чтобы выполнялось выделенное, иногда для объектов куда сложнее, чем написать оператор порядка.
Здравствуйте, Erop, Вы писали: .>>Правда всё равно в реальной жизни это бесполезно, т.к. размер стека жутко ограничен. E>Странно. В известных мне операционках, обычно можно отматать столько стэка, сколько надо... E>Пишешь нужное число в заголовок exeшника и всё...
Зачем patch-ить exe-файл? Серьёзный компилятор позволяет указать размер stack-а главного thread-а.
MSVC6:
меню «Project»,
пункт «Settings…»,
окно «Project Settings»,
страница «Link»,
выпадающий список «Category:» – выбрать «Output»,
группа «Stack allocations»,
поля ввода «Reserve:» и «Commit:».
BCB5:
меню «Project»,
пункт «Options…»,
окно «Project Options»,
страница «Linker»,
группа «PE file options»,
поля ввода «Min stack size:» и «Max stack size:».
Здравствуйте, Аноним, Вы писали:
А>2. Все STL-контейнеры неявно копируются. Опасно, если неявная операция дорога.
Это опасность "по невнимательности". Таких опасностей в С++ много и недостаками они в рамках идеологии С++ считаются не должны.
А>4. STL-контейнеры провоцируют использование size_t. Беззнаковость этого типа влечёт проблемы.
Это неверно. В STL-контейнерах никак не используется 'size_t'. Используется же там контейнерно-зависимый беззнаковый тип 'size_type'. Использование беззнакого типа вполне оправдано, ибо соответствует он заведомо неотрицательному значению. В данном случае наблюдается следование правилу "всегда использовать в программе только беззнаковые типы, кроме тех мест, где необходим знаковый тип", что более чем похвально.
Ошибки при использовании беззнаковых типов (в т.ч. в примерах ниже) обусловлены обычно 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'.
А>"Проблему size_t" можно решить несколькими способами:
Реальный способ тут только один — уситься пользоваться беззнаковыми типами как можно раньше. 99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях.
"Страховочное" использование знаковых типов допустимо для начинающего программиста, но не более.
А>5. Нельзя получить итератор по указателю на элемент контейнера за константное время.
В общес случае — нельзя. Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса".
А>6. Вместо метода empty удобнее был бы метод с позитивным смыслом, например has_elems (возвращает true <=> в контейнере есть хотя бы один элемент).
Неочевидно. Если и минус, то очень слабый.
А>7. Нельзя const_cast const_iterator в iterator. Я с этой проблемой на практике не сталкивался. Теоретически, может возникнуть при неудачном дизайне.
Слабый и странный "минус".
А>9. list А>9.1. list спроектирован так, что либо size за константное время, либо splice (вариант с 4-мя параметрами) за константное время (при условии, что allocator-ы равны).
А что делать? Так устроен мир. Именно к STL это мало относится.
А>10. string А>10.1. Если программа много работает с текстом, то string (или его аналог) — ходовой тип. При этом желательно, чтобы неявное копирование string-а было дешёвым. Для этого реализация string-а может использовать разделяемый (между несколькими string-ами) буфер с подсчётом ссылок. Но string спроектирован в mutable стиле, поэтому у него есть не-const методы begin, end, rbegin, rend, operator[] и at. Если реализация string-а считает ссылки, то эти методы делают copy-on-write (даже если вы не собираетесь ничего менять) и запрещают разделяемость буфера.
По-моему это вопрос качества реализации. Нет?
А>10.2. Нет завершающего '\0'.
Нет. Не вижу в этом минуса. А придумать ситуацию, когда это неудобно можно всегда.
Здравствуйте, LuciferMoscow, Вы писали:
_>>>да хотябы примеры доки... чтоб оценить E>>Если найду -- кину. E>>Там идея такая, что можно преобразовывать строки в числа и взад. Довольно легко и прямо. LM>boost::lexical_cast E>>При этом они там строки короче чего-то вообще не аллокируют никогда. LM>MS реализация std::string
Здравствуйте, 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 для словника английского языка например.
Узнаешь много интересного
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop wrote:
>> > Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. > .>Просто hash_map нестандарна... > Конечно это это плюс STL. Что же ещё? > Людям, как обычно нужно, не чтобы стандартно, а чтобы работалось и > дёшево переносилось > Можно хоть свой собственный hash_map с собой таскать всегда
Если надо, то можно использовать. Просто Шахтёр так уж очень категорично заявил — что ваще map фтопку.
Вообще странное заявление. Ведь это разные структуры данных, с разными вариантами использования, нельзя сказать, что
одно правильно, другое нет.
>> > Кроме того, string может иметь дорогой оператор копирования. Именно >> > поэтому его нельзя использовать для работы с большим массивом строк. >> > Плюс фрагментация памяти. > .>Тут же string в качестве ключа используется, копирование при помещении > в map всё равно будет. Какая разница? > Ну так в std::map<std::string> обычно есть где-то в недрах аналог > std::vector<std::string>. а std::vector любит время от времени
Кто тебе сказал? Там обычное дерево, по устройству скорее всего ближе к std::list.
> копировать свои потроха, при этом std::string обычно копируется > задорого, да ещё и кучу фрагментирует как подорванное
Думаю, там всё сводится к memcpy. А насчёт кучи... Трудно что-то определённое сказать, всё очень implementation defined.
> .>Со строками до нескольких килобайт думаю большой разницы не будет. > memcmp работает очень быстро. > Ну попробуй, например, родить hash_map и map для словника английского > языка например. > Узнаешь много интересного
Для словаря всё равно разумнее map использовать, т.к. частенько требуется иметь список слов отсортированный в
лексикографическом формате, а не как попало в хеше.
ЗЫЖ Хватит смайлики сообщениям в rsdn.cpp расставлять, нашел повод для веселья.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Кто тебе сказал? Там обычное дерево, по устройству скорее всего ближе к std::list.
Да всё равно вроде сортируют
Да и аллокаций вагон, кстати.
.>Думаю, там всё сводится к memcpy. А насчёт кучи... Трудно что-то определённое сказать, всё очень implementation defined.
Ну да. Это ещё больше портит картину, если требуется переносимость. Конечно то, что у тебя типа всё соответсвует стандарту и типа работает, но на одной платформе нормально работает, а на другой куча фрагментируется в каку и получается просто один своп, вместо работы программы, то что делать дальше -- . А то, что теоретики C++ при этом с умным видом говорят "ну это у вас реализация STL такая" конечно же помогает офигительно
.>Для словаря всё равно разумнее map использовать, т.к. частенько требуется иметь список слов отсортированный в .>лексикографическом формате, а не как попало в хеше.
Да? И зачем тебе отсортированный словник ангилйского языка "частенько"?
Читать на пенсии?
.>ЗЫЖ Хватит смайлики сообщениям в rsdn.cpp расставлять, нашел повод для веселья.
Так ведь смешно же
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop wrote:
> .>Кто тебе сказал? Там обычное дерево, по устройству скорее всего ближе > к std::list. > Да всё равно вроде сортируют
Ну почитай исходники что-ли, да разберись как оно работает.
Обычно сделано это: http://en.wikipedia.org/wiki/Red_Black_Tree
> Да и аллокаций вагон, кстати.
У тебя какой-то аллокатор особенный? При каждом вызове аллокации тебя бьёт током?
> .>Думаю, там всё сводится к memcpy. А насчёт кучи... Трудно что-то > определённое сказать, всё очень implementation defined. > Ну да. Это ещё больше портит картину, если требуется переносимость. > Конечно то, что у тебя типа всё соответсвует стандарту и типа работает, > но на одной платформе нормально работает, а на другой куча > фрагментируется в каку и получается просто один своп, вместо работы > программы, то что делать дальше -- . А то, что теоретики C++ при этом с > умным видом говорят "ну это у вас реализация STL такая" конечно же > помогает офигительно
Профайлер. Только профайлер.
Premature optimization is the root of all evil! (c)
А при реализации надо пользоваться только сложностными характеристиками алгоритмов.
> .>Для словаря всё равно разумнее map использовать, т.к. частенько > требуется иметь список слов отсортированный в > .>лексикографическом формате, а не как попало в хеше. > Да? И зачем тебе отсортированный словник ангилйского языка "частенько"? > Читать на пенсии?
Погляди как показывается список слов в той же Lingvo — отсортированный список с поиском as you type.
> .>ЗЫЖ Хватит смайлики сообщениям в rsdn.cpp расставлять, нашел повод для > веселья. > Так ведь смешно же
Может в rsdn.humor обсуждения перенести?
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
>> но на одной платформе нормально работает, а на другой куча >> фрагментируется в каку и получается просто один своп, вместо работы >> программы, то что делать дальше -- . А то, что теоретики C++ при этом с >> умным видом говорят "ну это у вас реализация STL такая" конечно же >> помогает офигительно .>Профайлер. Только профайлер. .>Premature optimization is the root of all evil! (c) .>А при реализации надо пользоваться только сложностными характеристиками алгоритмов.
Очень хорошо. Вызванный фрагментацией своп и без профайлера прекрасно заметен обычно
А вот как профайлер помогает в борьбе с ним --
Я был бы рад узнать методы
А вообще-то я ведь заранее написал конспект твоего ответа Он там сверху выделен...
.>Погляди как показывается список слов в той же Lingvo — отсортированный список с поиском as you type.
Хе-хе-хе. Я как-то читал исходники лингво. Там про STL ни слова и про структуры подобные std::map -- тоже
Там всё совсем-совсем иначе... Кроме того, там ещё и объединённый словник нескольких словарей...
Можешь, кстати, поинтересовать как там скролл работает... В смысле попробовать поскролировать разными способами... .>Может в rsdn.humor обсуждения перенести?
Ну можешь попробовать
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, Erop, Вы писали:
RO>>>Предлагаю реализовать аналог std::deque без итераторов. E>>А в чём проблема?
RO>
RO>std::deque<X> xs;
RO>for(std::deque<X>::const_iterator i = xs.begin(), i_e_ = xs.end(); i != i_e_; ++i)
RO>{
RO> . . .
RO>}
RO>
RO> RO>
RO>your::deque<X> xs;
RO>for . . . ?
RO>
Зависит от того, что тебе надо
Например так:
namespace my {
template<class T>
class deque {
public:
...
void PushFront( const T& t )
{
if( firstelemntIndex <= 0 )
allocSpaceInFront( size() );
assert( firstelemntIndex > 0 );
allocSpaceInFront--;
data[allocSpaceInFront] = t;
}
void PushBask( const T& t ) { data.push_back( t ); }
void PopFront() { assert( size() > 0 ); firstelemntIndex++; }
void PopBack() { assert( size() > 0 ); data.pop_back; }
const T& operaotr[]( int i ) const { assert( i >= 0 && i < size() ); return data[i + firstelemntIndex] }
int size() const { assert(firstelemntIndex); return elems.size() - firstelemntIndex; }
...
private:
std::vector<T> elems;
int firstelemntIndex;
...
};
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали: АТ>>Это опасность "по невнимательности". Таких опасностей в С++ много и недостаками они в рамках идеологии С++ считаются не должны. АТ>>Ошибки при использовании беззнаковых типов (в т.ч. в примерах ниже) обусловлены обычно 1) невнимательностью и 2) неоправданным смешением знаковых и беззнаковых типов. По этой причине, аргументами их считать сложно. АТ>>Реальный способ тут только один — учиться пользоваться беззнаковыми типами как можно раньше. АТ>>"Страховочное" использование знаковых типов допустимо для начинающего программиста, но не более. E>Это первая группа комментов. Если коротко, то так: "Увольте всех невнимательных программистов и напишите, наконец, прекрасную программу "Hellow World!" в одинчку. Внимательно, правильно и без этих всех глупых и труднообнаружимых ошибок! E>Так?
Если посмотреть на контрпримеры, то мне кажеться, что знаковость осмысленно используется только в значении -1 как признак того, что поиск неудачен.
Чем это лучше чем string::npos или vector::end()
Писать меньше? Но чем -1 лучше чем -10? Как отличить признак неудачи поиска от честной константы? Что делать в случае передачи отрицательного индекса в массив?
И таки исходный вопрос: многие ли операции в ваших программах действительно требуют работы со знаковыми типами и итераций по ним?
E> АТ>>Слабый и странный "минус". АТ>>Неочевидно. Если и минус, то очень слабый. АТ>>По-моему это вопрос качества реализации. Нет? АТ>>Нет. Не вижу в этом минуса. А придумать ситуацию, когда это неудобно можно всегда. АТ>>В общес случае — нельзя. Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса". E>Вторая большая группа "возражений". В переводе на русский: "Я не понял или не знаю что сказать"
По моему, всю эту группу вообше нельзя к минусам относить...
Чем has_elems лучше empty (кроме привычки к MFC)?
Зачем понадобиться конст-кастить итераторы (кроме плохого дизайна)?
Зачем нужен дополнительный '\0' в строке, которая может содержать любое количество этих '\0' (дополнить самому, если это так надо, религия не позволяет)?
E> E>Выводы: E>А выводы-то всё те же. Что мы видим с вами?
Что не надо пытаться применять подходы pure-C в STL.
Что в С-with-classes без шаблонов и исключений STL не только не нужен а даже, наверное, вреден.
P.S. Может я ошибаюсь, но если говорить про кадры, по моему проще выставить знание STL в требовании к вакансии и задать пару вопросов на собеседовании, чем приняв человека несколько месяцев обучать его работе с аналогом STL собственного изготовления.
Здравствуйте, strcpy, Вы писали: IID>>Вы серъезно так думаете о С++ программистах ? S>У нас в мухоср... Новосибирске ситуация именно такая.
А у нас в "мухоср... Новосибирске" ровно наоборот.
Здравствуйте, strcpy, Вы писали: S>Мало квалифицированнах программистов, которые владеют STL. S>Поэтому код на STL рискует стать трудносопровождаемым.
Как-то не представляется квалифицированный программист на С++ не владеющий STL.
Либо квалификация не очень, либо STL знает.
Здравствуйте, Tonal-, Вы писали:
T>Если посмотреть на контрпримеры, то мне кажеться, что знаковость осмысленно используется только в значении -1 как признак того, что поиск неудачен.
Странно. А вычисления с участием вычитания они типа редскость астрашенная?
T>И таки исходный вопрос: многие ли операции в ваших программах действительно требуют работы со знаковыми типами и итераций по ним?
Практически любое целое число в моих программах может оказаться отрицательным.
Пример такого числа: качество чего-нибудь. Если что-то получилось совсем плохо и качество отрицательное -- это повод для assert'а, а не для того, чтобы радоваться тому, что качество получилось где-то рядом с UINT_MAX
Ещё пример такого числа -- координаты точки (например на экране): x и y. И опять, хотя пикселей с отрицательными значениями коорлдинат не существует, тем не менее разность координат я хочу видеть знаковую, да и координаты углов окна, например, тоже
Вдруг я кусок окна задвину за границу экрана?
Ну и так дадее. Совершенно повсеместно. Специально для случая с индексом я приведу тебе один пример. А вообще-то был тут где-то недалеко здоровычй флейм про беззнаковые числа. Пиши туда?
for( int i = myArr.Size() - 5; i >= 0; i -= step )
sum += myArr[i];
E>> АТ>>>Слабый и странный "минус". АТ>>>Неочевидно. Если и минус, то очень слабый. АТ>>>По-моему это вопрос качества реализации. Нет? АТ>>>Нет. Не вижу в этом минуса. А придумать ситуацию, когда это неудобно можно всегда. АТ>>>В общес случае — нельзя. Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса". E>>Вторая большая группа "возражений". В переводе на русский: "Я не понял или не знаю что сказать" T>По моему, всю эту группу вообше нельзя к минусам относить... T>Чем has_elems лучше empty (кроме привычки к MFC)? T>Зачем понадобиться конст-кастить итераторы (кроме плохого дизайна)? T>Зачем нужен дополнительный '\0' в строке, которая может содержать любое количество этих '\0' (дополнить самому, если это так надо, религия не позволяет)?
ИМХО пример плохого дизайна -- это весь шаблон basic_string. Он позволяет создать некую, довольно безумную абстракцию, но совсем не позволяет создать строку в традиционном понимании этого слова
В принципе мне религия позволяет пойти ещё дальше и не то чтобы нолики куда-то добавлять, а вообще пользоваться другой C++ строкой
Вообще-то мне хочется, чтобы в строчке хранились символы. Ну на крайняк хитрые символы. Но таки символы.
Кроме того, мне хотелось бы, чтобы нули были толкьо в конце и т. д.
E>> E>>Выводы: E>>А выводы-то всё те же. Что мы видим с вами? T>Что не надо пытаться применять подходы pure-C в STL. T>Что в С-with-classes без шаблонов и исключений STL не только не нужен а даже, наверное, вреден.
Проблема в том, что то, что ты называешь С-with-classes не такой уж плохой язык. А шаблоны -- страшная всё-таки хреновина. Ну вот STL всё равно с нами. И всегда сложный. Даже если ты с шаблорнами пишешь, то всё равно он сожный
T>P.S. Может я ошибаюсь, но если говорить про кадры, по моему проще выставить знание STL в требовании к вакансии и задать пару вопросов на собеседовании, чем приняв человека несколько месяцев обучать его работе с аналогом STL собственного изготовления.
К сожалению так сделать нельзя. Просто потому что STL код реально плохо предсказуемо взрывается. А ещё потому, что для программирования всяких роеальных задач STL хронически мало. Так что всё равно прийдётся искать/учить ещё какую-нибудь хреновину
Ну а буст, ИМХО, совсем неприемлемо сложен и непредсказуем. Увы
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tonal-, Вы писали:
T>Как-то не представляется квалифицированный программист на С++ не владеющий STL. T>Либо квалификация не очень, либо STL знает.
Я бы осмелился сказать, что навык "квалифицированный программист" он внеязыковой.
То есть я с бОльшей радостью возьму себе сотрудника, который вообще не занет C++, но зато квалифицированный программист
А знание STL подразумевается у квалифицированного кодера на C++. При этом наш опыт кажет, что эти "квалифицированные кодеры" нихрена не "квалифицированные программисты". Мало того, второй навык похоже мешает вырабатываться первому Мне кажется, что это так из-за неправильной системы ценностей
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, gid_vvp, Вы писали:
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
Не бывает просто абстрактных "минусов". Бывают положительные и отрицательные свойства технологии применительно к конкретно заданной области применения. Я считаю, что STL и так создан на пределе возможностей C++, так что там, где он не достаточно хорош, там вина C++ а не собственно STL.
Здравствуйте, CrazyClown, Вы писали:
CC> Не бывает просто абстрактных "минусов". Бывают положительные и отрицательные свойства технологии применительно к конкретно заданной области применения. Я считаю, что STL и так создан на пределе возможностей C++, так что там, где он не достаточно хорош, там вина C++ а не собственно STL.
В целом я согласен с выделенным тезисом, но не согласен с выводами.
ИМХО STL наоборот в большинстве случаев он слишком хорош
Типа обычно можно и проще. Занчит лучше делать таки проще
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Tonal-, Вы писали:
T>>Если посмотреть на контрпримеры, то мне кажеться, что знаковость осмысленно используется только в значении -1 как признак того, что поиск неудачен. E>Странно. А вычисления с участием вычитания они типа редскость астрашенная?
Мы же не про вычисления вообще, а про итерации по контейнерам и адресацию в них, правильно?
А в этом разрезе, отрицательные величины как-то странненько смотряться.
Чем поведение контейнера при адресации [-10] должно отличаться от [4294967286]?
T>>И таки исходный вопрос: многие ли операции в ваших программах действительно требуют работы со знаковыми типами и итераций по ним? E>Практически любое целое число в моих программах может оказаться отрицательным.
Т.е. количество пользователей -5чел — вполне нормальная ситуация?
E>Пример такого числа: качество чего-нибудь. Если что-то получилось совсем плохо и качество отрицательное -- это повод для assert'а, а не для того, чтобы радоваться тому, что качество получилось где-то рядом с UINT_MAX
Этот ассерт будет не более информативен, чем сравнение с UINT_MAX/2 для беззнаковых.
А вот если в нём действительно будет проверяться допустимый ожидаемый диапазон...
E>Ещё пример такого числа -- координаты точки (например на экране): x и y. И опять, хотя пикселей с отрицательными значениями коорлдинат не существует, тем не менее разность координат я хочу видеть знаковую, да и координаты углов окна, например, тоже E>Вдруг я кусок окна задвину за границу экрана?
Опять же, часто ли ты эти отрицательные координаты используються для индексации массива?
E>Ну и так дадее. Совершенно повсеместно. Специально для случая с индексом я приведу тебе один пример. А вообще-то был тут где-то недалеко здоровычй флейм про беззнаковые числа. Пиши туда? E>
for( int i = myArr.Size() - 5; i >= 0; i -= step )
E> sum += myArr[i];
Чуть длиннее:
if (myArr.Size() > 5)
accumulate(advance(myArr.rbegin(), 5), myArr.rend(); sum);
По моему, проблема тут таки не в STL, а в некотором смешении понятий:
Целое число как абцисса и как индекс в массиве это совершенно разные типы.
В первом случае знак вполне осмыслен, во втором нет.
То что часто их представляют одинаковым типом в языке — можно отнести к недостаткам языка.
В STL ввели итераторы — это представление позиции в контейнере. Т.е. попытка исправить этот недостаток.
Код с итераторами действительно становиться более безопасный в плане выхода за граници, как только это понимаешь.
E>>> T>>Зачем нужен дополнительный '\0' в строке, которая может содержать любое количество этих '\0' (дополнить самому, если это так надо, религия не позволяет)? E>ИМХО пример плохого дизайна -- это весь шаблон basic_string. Он позволяет создать некую, довольно безумную абстракцию, но совсем не позволяет создать строку в традиционном понимании этого слова
E>>> E>>>Выводы: E>>>А выводы-то всё те же. Что мы видим с вами? T>>Что не надо пытаться применять подходы pure-C в STL. T>>Что в С-with-classes без шаблонов и исключений STL не только не нужен а даже, наверное, вреден. E>Проблема в том, что то, что ты называешь С-with-classes не такой уж плохой язык. А шаблоны -- страшная всё-таки хреновина. Ну вот STL всё равно с нами. И всегда сложный. Даже если ты с шаблорнами пишешь, то всё равно он сожный
Я не утверждаю что он плохой.
Он несколько другой.
Ну и код, с применением шаблонов часто получается компактнее и быстрее.
Ну а понимание — дело наживное.
T>>P.S. Может я ошибаюсь, но если говорить про кадры, по моему проще выставить знание STL в требовании к вакансии и задать пару вопросов на собеседовании, чем приняв человека несколько месяцев обучать его работе с аналогом STL собственного изготовления. E>К сожалению так сделать нельзя. Просто потому что STL код реально плохо предсказуемо взрывается. А ещё потому, что для программирования всяких роеальных задач STL хронически мало. Так что всё равно прийдётся искать/учить ещё какую-нибудь хреновину E>Ну а буст, ИМХО, совсем неприемлемо сложен и непредсказуем. Увы
С предсказуемостью и переносимостью спорить не буду.
Но опять же — это не проблемы STLя и даже не стандарта, как такового...
Перенос сколько-нибудь сложного кода даже между разными компиляторами дело не лёгкое.
И если для поддерживаемой платформы нет вменяимого компилятора, то даже идеальная стандартная библиотека не поможет...
Другое дело, что собственный код в таком случае проще адаптируется.
Здравствуйте, Erop, Вы писали:
E>В целом я согласен с выделенным тезисом, но не согласен с выводами. E>ИМХО STL наоборот в большинстве случаев он слишком хорош E>Типа обычно можно и проще. Занчит лучше делать таки проще
Делать проще громоздкий синтаксис C++ не позволяет. Так что приходится делать так, как делает STL.
Конечно же, на каждый случай применения STL найдутся сотни частных случаев, когда можно сделать проще и тупее — ну так это беда любого слишком общего решения.
Здравствуйте, Tonal-, Вы писали:
T>Здравствуйте, strcpy, Вы писали: S>>Мало квалифицированнах программистов, которые владеют STL. S>>Поэтому код на STL рискует стать трудносопровождаемым. T>Как-то не представляется квалифицированный программист на С++ не владеющий STL. T>Либо квалификация не очень, либо STL знает.
А зачем "знать" STL если её не использовать?
Точно так же можно сказать, что то кто не знает MFC -- неквалифицированный программист.
Знать нужно не STL, а приёмы программирования , в том числе и те, которые в STL используются.
Ну и разумеется, знать алгоритмическую базу.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Это неверно. В STL-контейнерах никак не используется 'size_t'. Используется же там контейнерно-зависимый беззнаковый тип 'size_type'. Использование беззнакого типа вполне оправдано, ибо соответствует он заведомо неотрицательному значению. В данном случае наблюдается следование правилу "всегда использовать в программе только беззнаковые типы, кроме тех мест, где необходим знаковый тип", что более чем похвально.
1 — Софистика — нельзя априори говорить о значении, мы отлаживаем программу и может быть все что угодно
2 На соседней ветке Вы говорили об том что беззнаковые вычисления более быстрые. Все с точностью наоборот. Для целых они попросту одинаковы. А преобразования из в плавающие могут быть выполнены одной командой для знаковых.
3 Сравнений беззнаковых не существует, уж не знаю что там в стандардарте. Я пишу всегда проверу для индексов 0<=I && I<N . По идее это можно заменить на одну проверку signed(I)<N.
тоесть беззнаковых операций сравнения не существует, уж не знаю как там по стандару. Возможно они есть у МС по какомуту ключу компилятора. Но это уже не актуально
баг ... P>3 Сравнений беззнаковых не существует, уж не знаю что там в стандардарте. Я пишу всегда проверу для индексов 0<=I && I<N . По идее это можно заменить на одну проверку UNsigned(I)<N.
Здравствуйте, Tonal-, Вы писали:
T>Опять же, часто ли ты эти отрицательные координаты используються для индексации массива?
E>>Ну и так дадее. Совершенно повсеместно. Специально для случая с индексом я приведу тебе один пример. А вообще-то был тут где-то недалеко здоровычй флейм про беззнаковые числа. Пиши туда? E>>
for( int i = myArr.Size() - 5; i >= 0; i -= step )
E>> sum += myArr[i];
T>Чуть длиннее: T>
if (myArr.Size() > 5)
T> accumulate(advance(myArr.rbegin(), 5), myArr.rend(); sum);
Что характерно, step !всегда= 1 и std::advance принимает ссылку. Понятно, что это не так уж и существенно, и что Boost решает обе проблемы, но не надо бежать впереди паровоза.
А с другой стороны, если вышеуказанное должным образом переделать в итераторы, то оно будет работать любыми итераторами, включая std::list-овые.
Здравствуйте, Андрей Тарасевич, Вы писали: P>3 Сравнений беззнаковых не существует, уж не знаю что там в стандардарте. Я пишу всегда проверу для индексов 0<=I && I<N . По идее это можно заменить на одну проверку signed(I)<N.
Пардон все правильно действительно можно и быстрей беззнаково Ошибся — наверно плохо отдохнул
Здравствуйте, Tonal-, Вы писали:
T>А в этом разрезе, отрицательные величины как-то странненько смотряться. T>Чем поведение контейнера при адресации [-10] должно отличаться от [4294967286]?
У индексов есть два момента.
1) нередко бывает так, что в процессе итерации удобно выходить за границу массива, что и показывает, что пора заканчивать итерацию
2) Бывает таки так, что индексы участвуют в вычислениях. Например часто хочется узнать какой из индексов больше и на сколько . Или храниить какие-то диапазоны индексов, которые легко могут выходить за область индексов массива.
T>>>И таки исходный вопрос: многие ли операции в ваших программах действительно требуют работы со знаковыми типами и итераций по ним? E>>Практически любое целое число в моих программах может оказаться отрицательным. T>Т.е. количество пользователей -5чел — вполне нормальная ситуация?
Если речь о пользователях STL -- то да . Например так "Итого: -5 пользователнй STL, за прошлый день"
T>Этот ассерт будет не более информативен, чем сравнение с UINT_MAX/2 для беззнаковых. T>А вот если в нём действительно будет проверяться допустимый ожидаемый диапазон...
А если качество не ограниченно сверху ничем разумным? Вот, скажем пример оценки качества (кода): "Ваша премия за след. квартал составит столько-то долларов"
E>>Ещё пример такого числа -- координаты точки (например на экране): x и y. E>>Вдруг я кусок окна задвину за границу экрана? T>Опять же, часто ли ты эти отрицательные координаты используються для индексации массива?
Ну экран запросто можно считать двумерным массивом пикселей (в приниципе он им и является).
И хотя реальных обращений к экрану, за его пределами не выполняется, тем н менее координаты окон на экране удобно иметь знаковыми, хотя и не все координаты "пикселей" в таких окнах будут валидными. Зато мы сможем оперировать с окнами, у которых на экране находится только часть...
E>>Ну и так дадее. Совершенно повсеместно. Специально для случая с индексом я приведу тебе один пример. А вообще-то был тут где-то недалеко здоровычй флейм про беззнаковые числа. Пиши туда? E>>
for( int i = myArr.Size() - 5; i >= 0; i -= step )
E>> sum += myArr[i];
T>Чуть длиннее: T>
if (myArr.Size() > 5)
T> accumulate(advance(myArr.rbegin(), 5), myArr.rend(); sum);
Э-э-э а где тут слово srep?
T>По моему, проблема тут таки не в STL, а в некотором смешении понятий: T>Целое число как абцисса и как индекс в массиве это совершенно разные типы. T>В первом случае знак вполне осмыслен, во втором нет.
А в чём разница?
T>Код с итераторами действительно становиться более безопасный в плане выхода за граници, как только это понимаешь.
Он не только более безопасный, но ещё и менее гибкий
А вообще-то я согласен, что вопрос о беззнаковых индексах и о итераторах связан, но не так прямо тут уже была больискошая дискуссия на эту тему
лучше флеймить там
E>>>> E>>Проблема в том, что то, что ты называешь С-with-classes не такой уж плохой язык. А шаблоны -- страшная всё-таки хреновина. Ну вот STL всё равно с нами. И всегда сложный. Даже если ты с шаблорнами пишешь, то всё равно он сожный T>Я не утверждаю что он плохой. T>Он несколько другой. T>Ну и код, с применением шаблонов часто получается компактнее и быстрее. T>Ну а понимание — дело наживное.
Проблемы с шаблонами у меня обычно не из-за понимания, во всяком случае у меня, а с другим. Два есть источника обычно. Один состоит в излишнем оптимизме многих наших разрабочиков, при оценке чвоих сил при написании шаблонов. А второй происходит при поддержке шаблонного кода. Просто шаблоны в C++ сделаны стрёмно. Они слишком гибкие, и их очень неудобно и невыразительно можно ограничивать в гибкости. Ну и нет нужных сервисов (скажем списков типов или полей), но, зато это всё можно реализовать через одно место
А что касается "более быстрого и компактного кода с шаблонами", то у меня есть такое вот наблюдение над задачами, которые реально возникают даже при разработке очень очень сложных и наукоёмких программ. Такие проблемы, ИМХО, хорошо решаются в следующем порядке
1) Если можно как-то просто и естественно сделать без виртуальных функций, то это решение оказывается самым хорошим, быстрым и поддерживаемым.
2) Если п. 1 не получился, а с виртуальными функциями, но без шаблонов, таки получается сделать как-то естественно и просто, то обычно это и есть хорошее решение.
3) Если и 1 и 2 не прошли, то значит задача реально небанальная. И, возможно, приминив шаблоны её удастся решить приемлемо неплохо.
При этом уровень подготовки спеца, который может хорошо решать задачи такой сложности растёт в этом списке довольно значительно...
T>Перенос сколько-нибудь сложного кода даже между разными компиляторами дело не лёгкое. T>И если для поддерживаемой платформы нет вменяимого компилятора, то даже идеальная стандартная библиотека не поможет... T>Другое дело, что собственный код в таком случае проще адаптируется.
Да. И даже если компилятор есть...
Я был удивлён в своё время, когда вдруг понял, что переносимость в смысле C++ имеет мало отношения к переносимости программ в утилитарном смысле. То есть как сделать так, чтобы программа, которая работала на одной платформе, заработала на другой
Но в любом случае флейм про signed\unsigned лучше продолжать тут :)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, CrazyClown, Вы писали:
E>>Типа обычно можно и проще. Занчит лучше делать таки проще
CC> Делать проще громоздкий синтаксис C++ не позволяет. Так что приходится делать так, как делает STL. CC> Конечно же, на каждый случай применения STL найдутся сотни частных случаев, когда можно сделать проще и тупее — ну так это беда любого слишком общего решения.
+1!
Так и я говорю, что STL слишком общая (абстрактная) библиотека
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Андрей Тарасевич, я писал:
АТ>>В общес случае — нельзя. Но это ограничение имеет свои оправдания, свои плюсы и минусы. Странно видеть его в качестве "минуса".
E>...Интересно бы узнать плюсы такого ограничения, например E> АТ>>99% целых типов в профессионально написаной среднестатистической программе должны являться беззнаковыми. Знаковые типы используются только в исключительных случаях. E>А вот это совсем интересно. Всё-таки чем так сильно C++ отличается от остальных процедурных и ООП языков? Почему-то в остальных вполне получается писать хорошие программы вообще без использования беззнаковых целых, и только на C++ 99% должны быть беззнаковыми?
E>Ещё интересно, как ты обходишься без типа unsigned double. Тяжело наверное?..
E> E>Выводы: E>А выводы-то всё те же. Что мы видим с вами? E>А вилим мы то, что STL очень заточен под идеологически правильные споры, под написание сверхкорректного кода каких-то мифических прекрасных сэмплов, каким-то не менее мифическими сверхвысококвалифицированными, сверхвнимательными и сверхаккуратными программистами. E>Либо для обучения этих спецов (конечно, ещё Суворов говаривал, что в учении должно быть тяжело
E>А для тех, кто хочет что-то такое программировать в практических целях, например, чтобы продать, STL не выгодный какой-то. Так как далёк он от практики. Вопросы, которые важны для кого-то, кто пишет программы на практике, не являются минусами или являются особенностями реализации (ну вот есть у тебя такая особенность. А делать-то чего? , как будто реализация не может угробить и прекрасную идею ), операции со строками не важны, важно, чтобы можно было родить строку из любых объектов. Напрмиер из умныз указателей на открытые файлы, скажем, ну и так далее и тому подобное
А с чем ты собственно несогласен и почему не стал это писать, равно как и отвечать на выделенные вопросы?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, Tom, Вы писали:
S>>>>В действительности, даже такие структуры как std::map<string> достаточно быстры, Ш>>>"За такие структуры у нас увольняют." (c) мой Tom>>А можно по подробнее?
Ш>Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. Ш>Кроме того, string может иметь дорогой оператор копирования. Именно поэтому его нельзя использовать для работы с большим массивом строк. Ш>Плюс фрагментация памяти.
вопрос был почему увольняют а не почему хэш таблица лечше мапа.
Tom wrote: > Ш>Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. > Ш>Кроме того, string может иметь дорогой оператор копирования. Именно > поэтому его нельзя использовать для работы с большим массивом строк. > Ш>Плюс фрагментация памяти. > > вопрос был почему увольняют а не почему хэш таблица лечше мапа.
Ага, я тоже так и не понял. Мало того, выяснилось, что хаш-таблица слегка тяжелее мапа, т.к. помимо самих строк,
хранятся ещё и хеши. А разница лишь в сложности поиска по ключу.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Ага, я тоже так и не понял. Мало того, выяснилось, что хаш-таблица слегка тяжелее мапа, т.к. помимо самих строк, .>хранятся ещё и хеши. А разница лишь в сложности поиска по ключу.
скорее всего за злостное нарушение должностной инструкции. Но это так, мысли над ГК. А так лучше конечно дождаться ответа Шахтёра
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tonal-, Вы писали: T>А если серьёзно, то это расширение gcc всего лишь синтаксическая надстройка над alloca+placement new. T>Сочинить собственный велосипед в эту тему — тривиально.
В MSVC6 лучше не использовать alloca. У меня был случай:
В Debug-конфигурации всё работало, но в Release-конфигурации компилятор почему-то встроил (inline) функцию SmallFunc. Во время работы программы stack исчерпывался (по умолчанию резервируется мегабайт виртуальных адресов) и возбуждалось stack overflow.
Здравствуйте, Пётр Седов, Вы писали:
ПС>В Debug-конфигурации всё работало, но в Release-конфигурации компилятор почему-то встроил (inline) функцию SmallFunc. Во время работы программы stack исчерпывался (по умолчанию резервируется мегабайт виртуальных адресов) и возбуждалось stack overflow.
ничего удивительного в эжтом всём нет. Современные компиляторы (и даже VC6 ) пытаются использовать всю доступную в месте вызова инфу о теле функции. alloca вообще лучше в C++ не использовать. Есть намного более удачные техники...
Ну и где-то по ходу пьесы пишешь такие буфера и всё
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>Немного не вник, а чем это лучше std::vector<char>?
Потому и возник вопрос.
Отличеи вот в этом:
char buffer[standardBufferSize];
.>Потом, дело не в буферах, а в том, что alloca использует стек, а не динамическую память. А следовательно, по идее, .>должно быть быстрее.
А CAutoBuffer тоже использует стэк...
Идея такая, что для конкретного места в коде, где тебе хочется поиспользовать alloca пишешь
CAutoBuffer<CommonCaseBufferSize> bufferHolder;
void* const buffer = bufferHolder.Reserve( currentCaseBufferSize );
// Тут используем буфер, как нам надо...
В результате пока размер запроса типичный всё хорошо, мы работаем как на alloca, а если вдруг случится слишком большой запрос, то мы аллокируем память из кучи, а потом освободим её.
Коенчно можно сделать хитрый allocator для std::vector, но это, ИМХО, менее понятно, удобно. Кроме того человек, которому я давал совет, вроде бы не в восторге от STL.
Ну и главное. Если бы я привел пример с аллоктором STL, то ещё меньше было бы шансов что-то понять
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tom, Вы писали:
Tom>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, Tom, Вы писали:
S>>>>>В действительности, даже такие структуры как std::map<string> достаточно быстры, Ш>>>>"За такие структуры у нас увольняют." (c) мой Tom>>>А можно по подробнее?
Ш>>Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. Ш>>Кроме того, string может иметь дорогой оператор копирования. Именно поэтому его нельзя использовать для работы с большим массивом строк. Ш>>Плюс фрагментация памяти.
Tom>вопрос был почему увольняют а не почему хэш таблица лечше мапа.
Вообще это шутка конечно, но не совсем.
Этим летом был у меня на практике один студент.
Дал я ему несложную задачу -- реализовать FFT.
Он его реализовал так, что работало медленнее прямой реализации FT.
Причина -- в бездумном использовании STL.
Вот тогда то и родилась эта фраза.
STL в руках начинающего программиста -- орудие страшной разрушительной силы.
Человек, который пришел работать, должен делать что-то полезное.
Если он начинает делать что-то вредное (а STL как ни странно этому очень способствует), то наверно такой человек в коллективе не нужен.
Мне известны несколько реальных примеров когда серьёзные проекты были безнадежно испорчены благодаря STL, приходилось код выбрасывать на помойку и переделывать.
Шахтер wrote:
> STL в руках начинающего программиста -- орудие страшной разрушительной силы. > Человек, который пришел работать, должен делать что-то полезное. > Если он начинает делать что-то вредное (а STL как ни странно этому очень > способствует), то наверно такой человек в коллективе не нужен. > > Мне известны несколько реальных примеров когда серьёзные проекты были > безнадежно испорчены благодаря STL, приходилось код выбрасывать на > помойку и переделывать.
Да, согласен. Вещь тяжелая для начинающих. Но вообще говоря сам язык такой. Мне до сих пор с ужасом вспоминается
char *sLoop = new char[4];
_itoa(i, sLoop, 10);
string strField = fp1 + sLoop + fp2;
char *str = new char[255];
for (int i=0; i<=sizeof(strField); i++)
str[i] = strField[i];
_bstr_t impFieldName(str);
// думаю, очевдно, что delete нигде не было. ;)
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Smal wrote:
>> Это что за хоррор? .>Да один начинающий погроммист однажды мне выдал в моём проекте.
Ну дык тут не незнание STL. Здесь непонимание C++ как такового.
Особенно порадовало .>for (int i=0; i<=sizeof(strField); i++)
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, Tom, Вы писали:
Tom>>Здравствуйте, Шахтер, Вы писали:
Ш>>>Здравствуйте, Tom, Вы писали:
S>>>>>>В действительности, даже такие структуры как std::map<string> достаточно быстры, Ш>>>>>"За такие структуры у нас увольняют." (c) мой Tom>>>>А можно по подробнее?
Ш>>>Для хранения строк обычно используют всё-таки хеш таблицы, а не деревья. Ш>>>Кроме того, string может иметь дорогой оператор копирования. Именно поэтому его нельзя использовать для работы с большим массивом строк. Ш>>>Плюс фрагментация памяти.
Tom>>вопрос был почему увольняют а не почему хэш таблица лечше мапа.
Ш>Вообще это шутка конечно, но не совсем.
Ш>Этим летом был у меня на практике один студент. Ш>Дал я ему несложную задачу -- реализовать FFT. Ш>Он его реализовал так, что работало медленнее прямой реализации FT. Ш>Причина -- в бездумном использовании STL.
Ш>Вот тогда то и родилась эта фраза.
Ш>STL в руках начинающего программиста -- орудие страшной разрушительной силы. Ш>Человек, который пришел работать, должен делать что-то полезное. Ш>Если он начинает делать что-то вредное (а STL как ни странно этому очень способствует), то наверно такой человек в коллективе не нужен.
Ш>Мне известны несколько реальных примеров когда серьёзные проекты были безнадежно испорчены благодаря STL, приходилось код выбрасывать на помойку и переделывать.
Smal wrote:
>> > Это что за хоррор? > .>Да один начинающий погроммист однажды мне выдал в моём проекте. > Ну дык тут не незнание STL. Здесь непонимание C++ как такового.
В том-то и дело. Имхо незнание STL обычно основывается на непонимании C++. Хотя всякие абстрактные понятия как
ассоциативный контейнер, итератор, аллокатор и т.п. тоже необходимы, но это опять же не относится непосредственно к
самой STL.
> Особенно порадовало
Ага. А меня как радовало. Ведь такой код работал... иногда.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Erop, Вы писали: T>>А в этом разрезе, отрицательные величины как-то странненько смотряться. T>>Чем поведение контейнера при адресации [-10] должно отличаться от [4294967286]? E>У индексов есть два момента. E>1) нередко бывает так, что в процессе итерации удобно выходить за границу массива, что и показывает, что пора заканчивать итерацию E>2) Бывает таки так, что индексы участвуют в вычислениях. Например часто хочется узнать какой из индексов больше и на сколько . Или храниить какие-то диапазоны индексов, которые легко могут выходить за область индексов массива.
random access iterator решают эти проблему, не так ли?
E>>>Ещё пример такого числа -- координаты точки (например на экране): x и y. E>>Вдруг я кусок окна задвину за границу экрана? T>>Опять же, часто ли ты эти отрицательные координаты используються для индексации массива? E>Ну экран запросто можно считать двумерным массивом пикселей (в приниципе он им и является). E>И хотя реальных обращений к экрану, за его пределами не выполняется, тем н менее координаты окон на экране удобно иметь знаковыми, хотя и не все координаты "пикселей" в таких окнах будут валидными. Зато мы сможем оперировать с окнами, у которых на экране находится только часть...
Я, я как то работал с окошкаим и пикселями!
И получалось, что координаты внутри окна, всегда только положительные.
А когда выводим окно на экран, то снача вычисляем то, что выводить будем (клипирование называется).
Опять же итерирования по отричательным координатам нет.
E>>>Ну и так дадее. Совершенно повсеместно. Специально для случая с индексом я приведу тебе один пример. А вообще-то был тут где-то недалеко здоровычй флейм про беззнаковые числа. Пиши туда? E>>>
for( int i = myArr.Size() - 5; i >= 0; i -= step )
E>>> sum += myArr[i];
T>>Чуть длиннее: T>>
if (myArr.Size() > 5)
T>> accumulate(advance(myArr.rbegin(), 5), myArr.rend(); sum);
E>Э-э-э а где тут слово srep?
Тут пргнал. Звиняйте step не заметил.
Как правильно сказал Roman Odaisky
проблему можно просто решить.
Причём решение подойдёт для всех stl контейнеров.
А вот как вы это будете для дерева и списка рисовать, и как, потом кто-то сможет понять, что делает эта куча кода...
Хотя, если подобных вычислений много, то может быть вам нужна библиотека работы с векторами и матрицами? Boost.uBLAS, например?
T>>По моему, проблема тут таки не в STL, а в некотором смешении понятий: T>>Целое число как абцисса и как индекс в массиве это совершенно разные типы. T>>В первом случае знак вполне осмыслен, во втором нет. E>А в чём разница?
В том, что массив всегда имеет конечный положительный размер, и начинается с 0го элемента?
T>>Код с итераторами действительно становиться более безопасный в плане выхода за граници, как только это понимаешь. E>Он не только более безопасный, но ещё и менее гибкий
У каждого свои недостатки. E>А вообще-то я согласен, что вопрос о беззнаковых индексах и о итераторах связан, но не так прямо E>тут уже была больискошая дискуссия на эту тему
лучше флеймить там
Ок.
E>>>>> E>А что касается "более быстрого и компактного кода с шаблонами", то у меня есть такое вот наблюдение над задачами, которые реально возникают даже при разработке очень очень сложных и наукоёмких программ. Такие проблемы, ИМХО, хорошо решаются в следующем порядке
E>1) Если можно как-то просто и естественно сделать без виртуальных функций, то это решение оказывается самым хорошим, быстрым и поддерживаемым. E>2) Если п. 1 не получился, а с виртуальными функциями, но без шаблонов, таки получается сделать как-то естественно и просто, то обычно это и есть хорошее решение. E>3) Если и 1 и 2 не прошли, то значит задача реально небанальная. И, возможно, приминив шаблоны её удастся решить приемлемо неплохо.
У меня есть несколько другое наблюдение:
Было написано 2 движка векторного графического редактора.
В разное время для подобных задачь.
Первый использовал в основном шаблоны, второй виртуальность.
Скорость отрисовки отличалась примерно в 2-3 раза, хотя второй работал с несколько более простыми данными.
К сожалению отношение простоты и понятности мне оценивать трудно — по причине авторства.
Но оба успешно работают до сих пор в промыщленных системах.
M>В одном конкретном случае зачастую проще свилосипедствовать, чем разбираться с алгоритмом STL или с особенностями контейнеров. Зачастую быстрее написать алгоритм чем искать его в справочнике (в смысле в хелпе). Кароче надо довольно длинный список в голове держать. Если, скажем, ф-я поиска подстроки есть всегда и везде, то реализовывать её самому мне в голову не придёт, а вот тотже find_if: "ХЗ — есть эта фича в STL или нет — быстрее самому написать. Может я её ещё и не запинаю в своём случае". Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
M>Согласен. Только почему-то не я один такой. Наверное потому,что для того что бы сказать что функция next_permutation есть в STL это нужно просто ЗНАТЬ. Ты не можешь об этом догадаться, как например ты можешь не знать, чтоо в boost::filesystem есть функция извлечени пути из полного имени файла, но при этом логично предположить, что она там есть. И в 1-ю очередь я загляну в хелп, ибо вероятность найти там желаеме высока. А в случае с STL ДОГАДАТЬСЯ о наличии там какой-то фичи — проблематично. Если я не уверен что там есть нужный мне алгоритм,то не буду тратить время на штудирование хелпа — я напишу свой, ибо мои поиски могут не увенчаться успехом и я в пустую потрачу драгоценное время. Если конечно передо мной не стоит задача "по максимуму использовать STL".
Здравствуйте, ghostrider, Вы писали:
G>Здравствуйте, gid_vvp, Вы писали:
_>>Hi All
_>>перечислите, на ваш взгляд, основные минусы STL _>>принимаются только ответы с аргументацией
G>1) Контейнеры STL не транзакционны. Т.е. если во время операции с контейнером не удалось выделить память, то после этого контейнер находится в неопределнном состоянии — уже не исходное, но еще не конечное. Соответственно типы, которые хранят данные в STL контейнерах тоже не будут транзакционными, если не прилагать специальных усилий и терять при этом эффективность. G>2) В случае невозможности выделения памяти контейнеры STL кидают исключение. Стало быть, вызывающий код обязан его обрабатывать. Если вы используете STL в программе, это не так страшно, а вот если пишете библиотеку ф-ций с использованием STL, то тем самым навязываете пользователю то, что он тоже должен обрабатывать исключения. Если Вы используете контейнеры только внутренне и аккуратно обрабатываете все исключения, то тогда еще не все потеряно. А вот если используете типы STL в параметрах ф-ций, тогда плохо дело.
G>Насколько я знаю, STL, который поставляется с Visual Studio эти недостатки имеет. Было бы интересно узнать, как обстоит дело в остальных реализациях.
G>А вообще очень красивая библиотека. Лично мне нравится, только из-за вышеперечисленного пользоваться ей нужно очень осторожно.
Можно кстати пример библиотеки контейнеры которой поддерживают транзакционность ?
Здравствуйте, Germes, Вы писали:
G>Можно кстати пример библиотеки контейнеры которой поддерживают транзакционность ?
Видимо таких мало
Правда меня это не удивляет, так как нужда в транзакционности надуманная
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Tonal-, Вы писали:
E>>2) Бывает таки так, что индексы участвуют в вычислениях. Например часто хочется узнать какой из индексов больше и на сколько . Или храниить какие-то диапазоны индексов, которые легко могут выходить за область индексов массива. T>random access iterator решают эти проблему, не так ли?
И как они решают ту проблему, что иногда удобно получать и невалидные значения индексов?
T>Я, я как то работал с окошкаим и пикселями! T>И получалось, что координаты внутри окна, всегда только положительные. T>А когда выводим окно на экран, то снача вычисляем то, что выводить будем (клипирование называется). T>Опять же итерирования по отричательным координатам нет.
Э-э-э? А при чём тут итерирование?
Вот у тебя окошко, которое задвинуто в позицию (-10, -20 ), а само окошко 100 Х 200 пикселей.
Конечно после клипирования у тебя останется прямоугольник (0 — 90 х 0 — 180), весь из себя положительный. А в оконных координатах получится прямоуголдьник (10 — 100 х 20 — 200). Но как ты собираешься хранить сам прямоугольник окна (или его позицию)?
T>Хотя, если подобных вычислений много, то может быть вам нужна библиотека работы с векторами и матрицами? Boost.uBLAS, например?
И давно его приспособили к деревьям?
T>В том, что массив всегда имеет конечный положительный размер, и начинается с 0го элемента?
И именно поэтому его естественно представлять как неотрицательное целое взятое по модулю какой-то степени двойки?
E>>тут уже была больискошая дискуссия на эту тему
T>К сожалению отношение простоты и понятности мне оценивать трудно — по причине авторства. T>Но оба успешно работают до сих пор в промыщленных системах.
+1
Конечно динамический полиморфизм обычно медленнее. Но часто это не важно. Обычно если надо действительно быстро, то надо менять архитектуру
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Programador, Вы писали:
P>Не так давно я узнал, когда именно г-ну Степанову пришла идея библиотеки STL — когда он находился в отделении интенсивной терапии (после отравления рыбой) в, как он сам написал, "delirium state", по-просту — в состоянии БРЕДА.
P>Этот малеьнкий фактик очень удачно вписался в мои собственные представления об STL и самом языка С++. В предельно короткой форме: STL — это просто болезненный бред.
P>Бред относится к авторам библиотеки, а болезненный — это состояние ее пользователей.
P>Уже с самого начала STL производит впечатление чего-то монстроидального и совершенно непонятного. Это нагромождение template'd классов (яязык не поворачивается называть их объектами, это просто АТД-переростки) с огромным количество параметров и морем методов с весьма непонятными названиями. P> ................................. P>[/q]
Да хоть в наркотическом опьянении он её писал. Какая мне разница. Библиотека прекрасно отлажена, и есть хоть какой-то стандарт. Лучше работать с одним корявым (?) вектором, чем с десятью супер-векторами, запоминая разницу между ними, тратя время на отладку,поддержку, документацию и т.п.
Здравствуйте, gid_vvp, Вы писали:
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
Опять подняли?
Есдинственный минус — буква S.
Из-за нее я не могу быть уверен в том, что std::sort работает за n log n, не знаю, насколько эффективна list::splice. Из-за нее я должен ориентироваться на самую слабую реализацию — я не могу сказать: «библиотека требует Super Template Library 1.6.8+».
И т. п.
До последнего не верил в пирамиду Лебедева.
Re[5]: плюсы STL
От:
Аноним
Дата:
30.03.07 15:59
Оценка:
Здравствуйте, alzt, Вы писали:
A>Здравствуйте, Programador, Вы писали:
Вообщето это писал другой человек, Там приведена ссылка http://steps3d.narod.ru/tutorials/c-minus-minus.html
A>Да хоть в наркотическом опьянении он её писал. Какая мне разница.
Тексты не читабельны. Смена конттекста для тривиальных действий раздражает
A>Библиотека прекрасно отлажена, и есть хоть какой-то стандарт.
Какая именно баблиотека отлажена? Какой стандарт?
A> Лучше работать с одним корявым (?) вектором, чем с десятью супер-векторами, запоминая разницу между ними, тратя время на отладку,поддержку, документацию и т.п.
Корявый — CFile не засунеш. ну и т.д. Да все уже обсуждалось
E>А вообще идея продумать и написать небольшую юиюлиотеку, в которой будут E>массивы, списки, деревья и простые умные указатели E>Хэши и хэшмэпы (а не то прекрасное изделие, которое есть в stl под названием map) E>стредства управления памятью E>средства доступа к бинарным файлам E>средства сериализации в текст (хотя против потоков я как раз ничего не имею, просто хочется, чтобы всё совместимо осталось) E>средства сереализации в бинарный архив E>система исключений E>строчки.
E>И типа более или менее всё -- она позитивная весьма.
Классная идея Осталась спроектировать и реализовать эту библиотеку так чтобы она удовлетворяла потребностям ну хотя бы 90% программистов Потому что одному хочется в контейнеры пихать вот такие вот классы, другому — эдакие, но обоим хочется чтобы всё это было просто для понимания и лаконично выглядело в использовании. Ну и заодно сделать чтобы эта библиотека компилировалась и работала безбажно и желательно — эффективно на всём зоопарке компиляторов, среди которых есть довольно древние и довольно экзотичные. Да, и ещё не забыть пропихнуть эту библиотеку в массы, так чтобы её грабли и грабельки, которые будут в дизайне и/или имплементации (а они будут обязательно) — были описаны и известны широкому кругу пользователей библиотеки. Не то что бы задача неразрешимая — но ИМХО очень и очень непростая.
STL хоть как-то эту задачу решает. Реальной альтернативы ему не видно Буде такая появится на горизонте — я ей с удовольствием воспользуюсь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: минусы STL
От:
Аноним
Дата:
31.03.07 15:30
Оценка:
Здравствуйте, Left2, Вы писали:
E>>А вообще идея продумать и написать небольшую юиюлиотеку, в которой будут E>>массивы, списки, деревья и простые умные указатели E>>Хэши и хэшмэпы (а не то прекрасное изделие, которое есть в stl под названием map) E>>стредства управления памятью E>>средства доступа к бинарным файлам E>>средства сериализации в текст (хотя против потоков я как раз ничего не имею, просто хочется, чтобы всё совместимо осталось) E>>средства сереализации в бинарный архив E>>система исключений E>>строчки.
E>>И типа более или менее всё -- она позитивная весьма.
L>желательно — эффективно на всём зоопарке компиляторов, среди которых есть довольно древние и довольно экзотичные.
Насчет эффективности — СТЛ насилие над компиляторами. И они не очень давно научились ее эффективно компилить
L> Да, и ещё не забыть пропихнуть эту библиотеку в массы, так чтобы её грабли и грабельки, которые будут в дизайне и/или имплементации (а они будут обязательно) — были описаны и известны широкому кругу пользователей библиотеки. Не то что бы задача неразрешимая — но ИМХО очень и очень непростая.
STLport насколько я понимаю одним человеком сделан. Вопрос собственно не в релизации, а в несколько кривом дизайне ( http://rsdn.ru/Forum/Message.aspx?mid=2095037&only=1
Здравствуйте, Аноним, Вы писали: А>STLport насколько я понимаю одним человеком сделан.
STLport основана на SGI STL (здесь):
STLport Story by Boris Fomitchev
First Step
I started STLport project in Jan'97, shortly after first release of SGI STL. Back then, I was working for Moscow Center for SPARC Technology. I made a quick-and-dirty port of SGI STL for gcc-2.7.2 and SUN CC 4.2 for internal use. Very proud of myself, I submitted my changes back to SGI team. Matt Austern (still leading library developer) was kind enough to respond to me. However, I realized SGI team were not interested at all in extra portability. So I built my own Web page and started distributing my humble port from there. I named it "Adapted SGI STL" (weird, huh ?). Reasonable name appeared only a few months later.
Здравствуйте, Пётр Седов, Вы писали:
ПС>Здравствуйте, Аноним, Вы писали: А>>STLport насколько я понимаю одним человеком сделан. ПС>STLport основана на SGI STL (здесь):
Бесхозный он какойто СТЛ. Я думаю MS в VC на него забила, поскольку это продукт SGI, а SGI вообще на него забила
Здравствуйте, Аноним, Вы писали:
A>>Здравствуйте, Programador, Вы писали: А>Вообщето это писал другой человек, Там приведена ссылка http://steps3d.narod.ru/tutorials/c-minus-minus.html
Извиняюсь. Надеюсь я Вас не сильно оскорбил .
A>>Библиотека прекрасно отлажена, и есть хоть какой-то стандарт. А>Какая именно баблиотека отлажена? Какой стандарт?
stl. Стандарт C++. Например, увидев:
//list<int> l;
l.push_back(10);
Я могу быть уверенным, что:
1) В списке есть хотя бы один элемент.
2) Этот элемент находится в конце, указатель на следующий элемент пуст (т.е равер end()).
3) Все предыдущие ссылки, которые я использовал (итератора) остались валидны.
4) Размер списка увеличился на один элемент.
Уже достаточно много. Многие свои разрабатываемые контейнеры могут не поддерживать по какой-либо причине эти условия (в целях оптимизации).
A>> Лучше работать с одним корявым (?) вектором, чем с десятью супер-векторами, запоминая разницу между ними, тратя время на отладку,поддержку, документацию и т.п. А>Корявый — CFile не засунеш. ну и т.д. Да все уже обсуждалось
Не думаю, что Вам станет удобнее, если у Вас будет множество векторов на все случаи жизни.
Согласен, всё уже обсуждалось. Мои посты были в тему "разработчику C++ stl знать не обязательно".
Ещё поясню, чтобы меня не поняли неправильно: наверное, можно найти серьёзный проект, где stl не нужен. Но это не значит, что программисту С++ не надо знать stl, это скорее означает, что ему можно забыть stl на время текущего проекта.
Здравствуйте, alzt, Вы писали:
A>Ещё поясню, чтобы меня не поняли неправильно: наверное, можно найти серьёзный проект, где stl не нужен. Но это не значит, что программисту С++ не надо знать stl, это скорее означает, что ему можно забыть stl на время текущего проекта.
Да нет. STL конечно надо знать, хотябы для того, чтобы осознанно отказатьяс от его использования
Другое дело -- это правильно принять решение об масшьтабах использования стандартной библиотеки начиная следующий проект
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, alzt, Вы писали:
A>Ещё поясню, чтобы меня не поняли неправильно: наверное, можно найти серьёзный проект, где stl не нужен. Но это не значит, что программисту С++ не надо знать stl, это скорее означает, что ему можно забыть stl на время текущего проекта.
Знать конечно нужно. И остородно использовать, особенно в серьезных проектах
А решил я производительность померять СТЛ. Правда асм в релизе не посмотрел толком. В дебаге СТЛ вообще кошмар. В дебаге велосипед в 20 раз быстрее в релизе в 3
Чет функцию сравнения не могу в параметры шаблона засунуть. Как можно?
Здравствуйте, Programador, Вы писали: P>А решил я производительность померять СТЛ. P>… P>// сортировка односвязного списка
Зачем сортировать список (std::list)? Может, лучше использовать std::set – в нём элементы всегда сортированы.
Здравствуйте, Пётр Седов, Вы писали:
ПС>Зачем сортировать список (std::list)? Может, лучше использовать std::set – в нём элементы всегда сортированы.
Вообще-то если тебе надо собрать 10 000 элементов, а потом отсортировать их, то сначаоа собрать, а потом отсортировать быстрее, вроде
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали: ПС>>Зачем сортировать список (std::list)? Может, лучше использовать std::set – в нём элементы всегда сортированы. E>Вообще-то если тебе надо собрать 10 000 элементов, а потом отсортировать их, то сначаоа собрать, а потом отсортировать быстрее, вроде
Так вроде в обоих случаях время = O(N * log(N)) (насколько я знаю, стандарт гарантирует, что set::insert работает за время O(log(set::size))). Хотя если надо сортировать по целым числам из маленького диапазона, то это можно сделать за линейное время (распихать элементы по вёдрам, а потом собрать по порядку).
Здравствуйте, Пётр Седов, Вы писали:
ПС>Так вроде в обоих случаях время = O(N * log(N)) (насколько я знаю, стандарт гарантирует, что set::insert работает за время O(log(set::size))). Хотя если надо сортировать по целым числам из маленького диапазона, то это можно сделать за линейное время (распихать элементы по вёдрам, а потом собрать по порядку).
чесно слово не знаю деревья. Но если вставка за O(log(set::size))) я думаю что она может и быть за O(log(set::size))), но при этом можно придумать такие данные что прийдется перевешивать значительное число данных с одних веток на другие. Кроме того сортировка может понадобьтся внезапно, или потребуется несколько вариантов.
А разговор собственно не за O(N * log(N)) а за O(N * log(N)) Меня интересует насколько алокаторы тормозят код
Здравствуйте, Programador, Вы писали:
P>А решил я производительность померять СТЛ. Правда асм в релизе не посмотрел толком. В дебаге СТЛ вообще кошмар. В дебаге велосипед в 20 раз быстрее в релизе в 3
Это бред а не сравнения. Мало того что в дебаг режиме ничего не инлайнится, но и многие STL имплементации, имеют дополнительный код и проверки в дебаг версии. Например, STLPort в дебаге, хранит и проверят принадлежность итераторов и границы. Вообще, лучше покажи задачу — я тебя уверяю, что, как минимум в 90% случаев решение с STL будет не медленнее чем велосипедное.
"To protect people you must slay people. To let people live you must let people die. This is the true teaching of the sword."
-Seijuro Hiko, "Rurouni Kensin"
Здравствуйте, Zigmar, Вы писали:
Z>Это бред а не сравнения. Мало того что в дебаг режиме ничего не инлайнится, но и многие STL имплементации, имеют дополнительный код и проверки в дебаг версии. Например, STLPort в дебаге, хранит и проверят принадлежность итераторов и границы. Вообще, лучше покажи задачу — я тебя уверяю, что, как минимум в 90% случаев решение с STL будет не медленнее чем велосипедное.
Эта имплиментация (VC6) не имеет дополнительного кода для дебага. А нетужную функцию list<>::sort я выбрал по незнанию . Почему-то думал что в СТЛ все нужное
Здравствуйте, Symon, Вы писали:
_>>перечислите, на ваш взгляд, основные минусы STL _>>принимаются только ответы с аргументацией S>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы?
После того, как я поработал с коллекциями в Java и .NET — я стал намного больше любить STL...
Здравствуйте, MasterZiv, Вы писали:
MZ>Symon пишет:
>> Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL >> не способствует читаемости программы?
MZ>Ну я считаю. Я даже больше считаю — что STL надо выкинуть на фиг из MZ>стандартной библиотеки (потому что отстой). Но что это изменит ?
за что ?
чем он Вам так насолил ?
И какая альтернатива?
Критикуя — предлагай
Alex34 пишет:
> MZ>Ну я считаю. Я даже больше считаю — что STL надо выкинуть на фиг из > MZ>стандартной библиотеки (потому что отстой). Но что это изменит ? > > за что ? > чем он Вам так насолил ?
Начинать заново весь этот спор, думаю, бессмысленно, на 16-ти страницах,
думаю, уже достаточно доводов как за, так и против. Прочитайте, наверное
будет понятнее.
Здравствуйте, demi, Вы писали:
D>... Так вот как вы сделаете это без запихивания всех методов внутрь объекта?
Всех? Что, действительно считаешь, что ни один из методов std::string нельзя было сделать не членом (и не другом) без потери возможности реализовать size() выполняющийся за O(1)?
Здравствуйте, igna, Вы писали:
I>Всех? Что, действительно считаешь, что ни один из методов std::string нельзя было сделать не членом (и не другом) без потери возможности реализовать size() выполняющийся за O(1)?
А зачем? Объясните, зачем это делать?
Есть string и есть его методы, с ним работающие. Нафига их выносить то?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>А зачем? Объясните, зачем это делать? CC>Есть string и есть его методы, с ним работающие. Нафига их выносить то?
Ответы на вопрос "What's wrong with the design of std::string?" в последних четырех item-ах вот этой книги:
v_m> И как GUI жить на embedded-железе, у которого единственный информационный v_m>интерфейс наружу — это подключенный к компорту терминал? ....
Угу. Вот так и живем без функции для перебора файлов в каталоге — не на всех же системах есть каталоги. Хорошо, хоть файлы оставили. Тоже, кстати, не на всех системах есть, наверное...
Здравствуйте, Vamp, Вы писали:
V>А не могли бы Вы объяснить своими словами?
Зачем давать доступ к приватным членам тем функциям, которые могут обойтись без этого, то есть зачем делать членами функции, которые без потери эффективности можно выразить через другие функции? Чтобы показать, что они являются частью интерфейса? Так интерфейс класса не совсем формальное понятие, к интерфейсу класса могут относится и функции, не являющиеся его членами. Об этом Саттер тоже писал, возможно в той же книге, у меня сейчас ее под рукой нет.
Привет всем.
Вот хотел всё спросить. Сам stl юзаю есстественно совместно с другими библиотеками ATL\WTL\MFC .
Из плюсов вижу —
1. Что дефакто евляется частью стандарта. Что позволяет без относительно большого гемороя переносить код в разные среды разработки и платформы.
Из минусов.
1. нечитабельность программы на мой взгляд.
2. Не развивается.
Зы вот кстать ещё вопрос — Кто как думает надо ли стараться уменьшать использование STL в win32 проектах?
Просто незнаю почему ... Может подсознательно почему то стремлюсь использовать больше Мелкософские библиотеки, теже CString CAtlArray нежели wstring vector. Хатя знаю что не всегда это есть хорошо. К примеру тотже std::map побыстрее CAtlMap. Интересно мнение экспертов по этому поводу. Кто как считает?
Здравствуйте, lollipop, Вы писали:
L>2. Не развивается.
Развивается, просто новые версии появляются одновременно со стандартом C++, а последний не чаще чем раз в 10 лет. Но пока можно использовать Boost.
L>Зы вот кстать ещё вопрос — Кто как думает надо ли стараться уменьшать использование STL в win32 проектах?
Кому как. C++ мультипарадигменный, на нем можно программировать в разных, иногда плохо совместимых друг с другом стилях. Я писал Addon для OpenOffice на C++, программа выглядела почти как на Java, только в два раза длиннее.
Здравствуйте, Шебеко Евгений, Вы писали:
ШЕ>"C++ слишком сложный"
А что, это неправда? Ничего против сложностей вообще, формальная логика или квантовая механика тоже сложны, но это объективная сложность, а в C++ немалая толика сложности искуственная, привнесенная. Понятно, что тяжелое наследство C, но и неортодоксальное мышление автора языка сыграло не последнюю роль.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>В этом Страуструп не столько "не прав", сколько допускает черезмерное упрощение, ориентируясь на начинающего программиста (его книга изобилует такими упрощениями).
Да? А можно ссылку, где Страуструп в этом признался? И может где-нибудь есть список "таких упрощений" Страуструпа?
Здравствуйте, igna, Вы писали:
I>Зачем давать доступ к приватным членам тем функциям, которые могут обойтись без этого, то есть зачем делать членами функции, которые без потери эффективности можно выразить через другие функции? Чтобы показать, что они являются частью интерфейса? Так интерфейс класса не совсем формальное понятие, к интерфейсу класса могут относится и функции, не являющиеся его членами. Об этом Саттер тоже писал, возможно в той же книге, у меня сейчас ее под рукой нет.
1) Методы находятся в интерфейсе класса не ради удобства их написания, а ради удобства использования класса, IMHO,
Хотя, возможно, стоит уметь объявлять свой метод"врагом"
2) Во многих случаях было бы, IMHO, последовательно, для всяких действий использовать внешине функции.
Скажем для округления float мы же используем внешние функции, а не методы?
Для выяснения длины const char* тоже. И т. д.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Угу. Вот так и живем без функции для перебора файлов в каталоге — не на всех же системах есть каталоги. Хорошо, хоть файлы оставили. Тоже, кстати, не на всех системах есть, наверное...
На "всех системах" каталоги устроены немного по-разному.
Хотя как-то обобщить конечно могли бы...
Кстати, то, что на некоторых системах нет каталогов не мешает иметь функцию итерации их содержимого, на "безкаталожных" системах её реализация как раз тревиальна... Намного хуже то, что на многих системх кроме каталогов бывают всякие другие похожие штуки с другими свойствами
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Cyberax, Вы писали:
C>После того, как я поработал с коллекциями в Java и .NET — я стал намного больше любить STL...
STL лучше чем ничего, конечно. И лучше безумных коллекций со встреонными в них иетраторами.
Но, если воспринимать STL, именно как библиотеку колелкций, то он явно очень слабый и недоделанный (смотрите буст тот же, в конце концов). И сделан как-то так, "грубой силой оптимизирующего компилятора".
Есть намного более разумно обустроенные библиотеки контйнеров, вообще-то. Ориентированные на реальные сценарии, а не так как в std::basic_string. Они, INHO лучше чем STL...
Всё таки в сравнении познаётся...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>Ага, я тоже так и не понял. Мало того, выяснилось, что хаш-таблица слегка тяжелее мапа, т.к. помимо самих строк, .>хранятся ещё и хеши. А разница лишь в сложности поиска по ключу.
А почему должна быть тяжелее?
Казалось бы в хэш-таблице надо хэши хранить (хотя это и не обязательно, кстати), а в std::map надо дерево организовывать...
Кроме того, даже если хэши и хранить, то их можно хранить отдельно, компакто, что лучше ложится на современные архитектуры с многоуровневым кэшированием памяти...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>В этом Страуструп не столько "не прав", сколько допускает черезмерное упрощение, ориентируясь на начинающего программиста (его книга изобилует такими упрощениями).
I>Да? А можно ссылку, где Страуструп в этом признался? И может где-нибудь есть список "таких упрощений" Страуструпа?
а зачем тебе ссылка?
Просто возьми его книжку и стандарт и сравни.
Здравствуйте, Erop, Вы писали:
E>Есть намного более разумно обустроенные библиотеки контйнеров, вообще-то. Ориентированные на реальные сценарии, а не так как в std::basic_string. Они, INHO лучше чем STL...
E>Всё таки в сравнении познаётся...
Еслия правильно помню, ты говоришь о библиотеке, которую сам и написал?
Наверное, в твоей библиотеке вектор можно проитерировать за O(log(N)) или даже за O(1), в отличие ориентированного не на реальные сценарии std::vector?
Здравствуйте, jazzer, Вы писали:
J>Если я правильно помню, ты говоришь о библиотеке, которую сам и написал? J>Наверное, в твоей библиотеке вектор можно проитерировать за O(log(N)) или даже за O(1), в отличие ориентированного не на реальные сценарии std::vector?
Я пользуюсь несколькими библиотеками контейнеров. Все лучше STL.
А про итерацию вектора -- это ты наверное иронизировал?
Или я тебя не понял.
А вот если мы говорим про пополнение вектора векторов, например, то уже интересное обсуждение начинается...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
J>>Если я правильно помню, ты говоришь о библиотеке, которую сам и написал? J>>Наверное, в твоей библиотеке вектор можно проитерировать за O(log(N)) или даже за O(1), в отличие ориентированного не на реальные сценарии std::vector?
E>Я пользуюсь несколькими библиотеками контейнеров. Все лучше STL.
Имя, сестра! Имя!
E>А про итерацию вектора -- это ты наверное иронизировал? E>Или я тебя не понял. E>А вот если мы говорим про пополнение вектора векторов, например, то уже интересное обсуждение начинается...
Здравствуйте, Erop, Вы писали:
E>STL лучше чем ничего, конечно. И лучше безумных коллекций со встреонными в них иетраторами. E>Но, если воспринимать STL, именно как библиотеку колелкций, то он явно очень слабый и недоделанный (смотрите буст тот же, в конце концов). И сделан как-то так, "грубой силой оптимизирующего компилятора".
Ну недаделность — это факт, да и устарела STL сильно. Ей уже больше 10 лет, как-никак. Я воспринимаю STL скорее как "руководство к действию" для создания коллекций.
Здравствуйте, jazzer, Вы писали:
J>Имя, сестра! Имя!
Приватные конторские и моя любимая биюлиотека.
E>>А вот если мы говорим про пополнение вектора векторов, например, то уже интересное обсуждение начинается...
J>
Это если ты сам можешь всю работу за контейнер сделать и предугадать заранее что кому когда и как.
Тогда и встроенный С'шный массив справится...
А вот если ты не знаешь какой reserve сделать, тогда вся мощь контейнеров STL становится видна миру
Убогая недоделанная переусложнённая поделка прошедших веков...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>А вот если ты не знаешь какой reserve сделать, тогда вся мощь контейнеров STL становится видна миру E>Убогая недоделанная переусложнённая поделка прошедших веков...
Если ты не можешь сделать reserve — тебе в любом случае придётся делать какой-то вариант экспоненциального увеличения буффера.
Тебе в любом случае как-то придётся делать копирование/перемещение элементов из старой коллекции в новую.
Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать.
Здравствуйте, Cyberax, Вы писали:
C>Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать.
О чём и речь...
Но это довольно существенный минус, IMHO.
Кроме того он не единственный.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, Erop, Вы писали:
E>>А вот если ты не знаешь какой reserve сделать, тогда вся мощь контейнеров STL становится видна миру E>>Убогая недоделанная переусложнённая поделка прошедших веков... C>Если ты не можешь сделать reserve — тебе в любом случае придётся делать какой-то вариант экспоненциального увеличения буффера.
ну либо воспользоваться std::deque.
Это при условии, что не нужно последовательное размещение элементов в памяти, естественно.
C>Тебе в любом случае как-то придётся делать копирование/перемещение элементов из старой коллекции в новую.
+1
C>Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать.
Это в "поделке прошедших веков" так
А уже в текущем драфте стандарта красным по белому перечеркнуто требование "T is CopyConstructible".
И, естественно, все методы вставки принимают ссылки на rvalue.
Здравствуйте, Erop, Вы писали:
E>2) Во многих случаях было бы, IMHO, последовательно, для всяких действий использовать внешине функции.
Согласен. И думаю даже, что возможно через какое-то время появится рекомендация по возможности использовать даже друзей, но не члены. Для меня это последовательное продолжение рекомендации по возможности не делать функции членами. Иначе сначала у нас функция f выражается в терминах функции g, и потому f — не член, g — член; потом дизайн класса меняется, и наоборот g выражается в терминах f, соответственно f становится членом, а g — нет; и всем клиентам приходится переходить на новый синтаксис.
Здравствуйте, v_m, Вы писали:
>> например qt... когда станет свободной v_m> билл гейтс будет против
А владельцев QT никто не спросит?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>а зачем тебе ссылка?
Просто рекомендация Страуструпа по возможности использовать int даже если отрицательные значения не используются мне в свое время не понравилась. И вот, хочу поторжествовать.
Здравствуйте, igna, Вы писали:
I>Просто рекомендация Страуструпа по возможности использовать int даже если отрицательные значения не используются мне в свое время не понравилась. И вот, хочу поторжествовать.
Ну дык верная рекомендация-то...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
J>>Имя, сестра! Имя! E>Приватные конторские и моя любимая биюлиотека.
твоя любимая библиотека общедоступна?
E>Это если ты сам можешь всю работу за контейнер сделать и предугадать заранее что кому когда и как. E>Тогда и встроенный С'шный массив справится...
ну контейнер еще много чего делает, кроме угадывания своего размера.
E>А вот если ты не знаешь какой reserve сделать, тогда вся мощь контейнеров STL становится видна миру E>Убогая недоделанная переусложнённая поделка прошедших веков...
см. мой ответ Cyberax-у.
Здравствуйте, Symon, Вы писали:
S>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы?
Дело не в STL, а в синтаксисе шаблонов.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, jazzer, Вы писали:
J>твоя любимая библиотека общедоступна?
AFAIK, нет, во всяком случае пока. Она самописная (не совсем "само", но группой товарищей) и так и называется MFL
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, LaptevVV, Вы писали:
S>>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы? LVV>Дело не в STL, а в синтаксисе шаблонов.
IMHO они органично оба в паре работают на дело снижения читабельности
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, LaptevVV, Вы писали:
S>>>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы? LVV>>Дело не в STL, а в синтаксисе шаблонов.
E>IMHO они органично оба в паре работают на дело снижения читабельности
Предлагаю сойтись на том что "это заговор", и закрыть тему Ибо уже не возможно это читать, а каждый раз интересно почитать мнение "отцов форума"
Здравствуйте, LuciferMoscow, Вы писали:
LM>boost::lexical_cast
А что, это быстро?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>2) Во многих случаях было бы, IMHO, последовательно, для всяких действий использовать внешине функции. E>Скажем для округления float мы же используем внешние функции, а не методы? E>Для выяснения длины const char* тоже. И т. д.
ИМХО наиболее ровный метод — дать возможность на уровне языка расширять класс после его обьявления невиртуальными функциями, не имеющими доступа к private/protected секции класса. С одной стороны — для компилятора это всего лишь синтаксический сахар, с другой — удобство использования класса будет соседствовать с удобством его расширения. А то попытка добавить пару методов в std::string или std::vector выливается в пару экранов кода, так что проще действительно это сделать внешней по отношению к классу функцией.
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, Symon, Вы писали:
S>>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы? LVV>Дело не в STL, а в синтаксисе шаблонов.
Вынужден согласиться
Но вот, к примеру, MFC-контейнеры (сейчас меня закидают помидорами ), хоть конечно и используют заглавные буквы (что я считаю читабельности только на пользу), предлагают достойную замену итераторам — POSITION. Было бы замечательно если бы MFC ещё и переносимостью обладала.
Здравствуйте, Left2, Вы писали:
L>ИМХО наиболее ровный метод — дать возможность на уровне языка расширять класс после его обьявления невиртуальными функциями, не имеющими доступа к private/protected секции класса. С одной стороны — для компилятора это всего лишь синтаксический сахар, с другой — удобство использования класса будет соседствовать с удобством его расширения. А то попытка добавить пару методов в std::string или std::vector выливается в пару экранов кода, так что проще действительно это сделать внешней по отношению к классу функцией.
Можно, конечно, и так. Типа первый параметр this называешь и поехали...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Symon, Вы писали:
S>Вынужден согласиться S>Но вот, к примеру, MFC-контейнеры (сейчас меня закидают помидорами ), хоть конечно и используют заглавные буквы (что я считаю читабельности только на пользу), предлагают достойную замену итераторам — POSITION.
Очень достойно, но, ИМХО, отстойно.
(Пардон, не удержался от рифмы).
S>Было бы замечательно если бы MFC ещё и переносимостью обладала.
И позволяла бы хранить объекты
Здравствуйте, jazzer, Вы писали:
C>>Если ты не можешь сделать reserve — тебе в любом случае придётся делать какой-то вариант экспоненциального увеличения буффера. J>ну либо воспользоваться std::deque.
Дека — это уже другой контейнер, со своими особенностями.
C>>Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать. J>Это в "поделке прошедших веков" так J>А уже в текущем драфте стандарта красным по белому перечеркнуто требование "T is CopyConstructible". J>И, естественно, все методы вставки принимают ссылки на rvalue.
То есть, наконец-то можно будет передвигаемые объекты класть?
Здравствуйте, Erop, Вы писали:
C>>Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать. E>О чём и речь... E>Но это довольно существенный минус, IMHO.
Это уже исправили
E>Кроме того он не единственный.
А можно список? Я ещё знаю не очень продуманую схему работы с аллокаторами, разве что.
Здравствуйте, Erop, Вы писали:
J>>твоя любимая библиотека общедоступна? E>AFAIK, нет, во всяком случае пока. Она самописная (не совсем "само", но группой товарищей) и так и называется MFL :)
Я как-то уже задавал этот вопрос, но, может быть, что-то изменилось.
Как в YFL выглядит поэлементный обход аналога std::deque?
И как в YFL выглядит поиск значения в массиве, про который известно, что он упорядочен по такому-то критерию?
Здравствуйте, Roman Odaisky, Вы писали:
RO>Я как-то уже задавал этот вопрос, но, может быть, что-то изменилось. RO>Как в YFL выглядит поэлементный обход аналога std::deque? RO>И как в YFL выглядит поиск значения в массиве, про который известно, что он упорядочен по такому-то критерию?
1) аналога std::deque нет. Пока был не нужен. Есть всякие другие структуры данных, которых нет в std
2) есть шаблонный метод Find
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Symon, Вы писали:
S>Интересно, кто-нибудь ещё кроме меня считает, что в целом семантика STL не способствует читаемости программы?
раз есть понятие stl-like кто-то считают что способствует но при этом им сам STL чемто не нравится. Например абсолютно все гуи имеют свое core в котором свой Xarray (или Xvector) и свой XString, даже недавнишний u++.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, jazzer, Вы писали:
C>>>Если ты не можешь сделать reserve — тебе в любом случае придётся делать какой-то вариант экспоненциального увеличения буффера. J>>ну либо воспользоваться std::deque. C>Дека — это уже другой контейнер, со своими особенностями.
Ну я вот не знаю, как иначе бороться с переаллокацией всего массива целиком.
C>>>Единственный минус STL — она не поддерживает перемещаемые объекты, ей приходится их всегда копировать. J>>Это в "поделке прошедших веков" так J>>А уже в текущем драфте стандарта красным по белому перечеркнуто требование "T is CopyConstructible". J>>И, естественно, все методы вставки принимают ссылки на rvalue. C>То есть, наконец-то можно будет передвигаемые объекты класть?
Здравствуйте, Cyberax, Вы писали:
E>>Кроме того он не единственный. C>А можно список? Я ещё знаю не очень продуманую схему работы с аллокаторами, разве что.
Ты, кстати, видел в драфте, что сделали с аллокаторами?
раздел 20.6, полюбопытствуй
Здравствуйте, jazzer, Вы писали:
C>>А можно список? Я ещё знаю не очень продуманую схему работы с аллокаторами, разве что. J>Ты, кстати, видел в драфте, что сделали с аллокаторами? J>раздел 20.6, полюбопытствуй
Что-то не внушает. Возможности возвращать умные указатели так и не добавили. Что делать со stateful-аллокаторами тоже непонятно (так как для контейнеров в swap() указано константное время).
Здравствуйте, igna, Вы писали:
E>>Ну дык верная рекомендация-то... I>Так ведь это упрощение.
Ну дык это ж гроссмейстер новичкам советует...
Как в книжках по шахматам: конь на краю доски — плохо.
А гроссмейстеры ж сплошь и рядом играют...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, KBH, Вы писали:
KBH>>Здравствуйте, Mazay, Вы писали:
M>>>Нет в СТЛ какой-то структурировнности, что-ли. Какого-то простого правила — "Вот это точно должно быть в СТЛ, а вот это — не стоит и искать там".
KBH>>Это не в STL нет структурированности, а в твоих знаниях оной.
M>Согласен. Только почему-то не я один такой. Наверное потому,что для того что бы сказать что функция next_permutation есть в STL это нужно просто ЗНАТЬ. Ты не можешь об этом догадаться, как например ты можешь не знать, чтоо в boost::filesystem есть функция извлечени пути из полного имени файла, но при этом логично предположить, что она там есть. И в 1-ю очередь я загляну в хелп, ибо вероятность найти там желаеме высока. А в случае с STL ДОГАДАТЬСЯ о наличии там какой-то фичи — проблематично. Если я не уверен что там есть нужный мне алгоритм,то не буду тратить время на штудирование хелпа — я напишу свой, ибо мои поиски могут не увенчаться успехом и я в пустую потрачу драгоценное время. Если конечно передо мной не стоит задача "по максимуму использовать STL".
MSDN, <algorithm> Members
Все функции на одной странице.
Здравствуйте, Cyberax, Вы писали:
C>Ну недаделность — это факт, да и устарела STL сильно. Ей уже больше 10 лет, как-никак. Я воспринимаю STL скорее как "руководство к действию" для создания коллекций.
Ну вот комитет сейчас изо всех сил руководствуется. В следующем году узнаем, до чего доруководствуется.
L>Зы вот кстать ещё вопрос — Кто как думает надо ли стараться уменьшать использование STL в win32 проектах?
Я обычно наоборот, стараюсь свести все к C++/STL. Я ленивый, мне лень переписывать много раз одно и тоже, хочется один раз написать и использовать где ни попадя. А STL худо-бедно стандарт, если на платформе есть современный компилятор C++, то мое барахло скомпилируется и будет работать.
L> Просто незнаю почему ... Может подсознательно почему то стремлюсь использовать больше Мелкософские библиотеки, теже CString CAtlArray нежели wstring vector. Хатя знаю что не всегда это есть хорошо. К примеру тотже std::map побыстрее CAtlMap. Интересно мнение экспертов по этому поводу. Кто как считает?
Я как можно большую часть кода стараюсь писать независимо от платформы. Мало ли на подо что завтра писать придется.
Очевидно тем же чем и неинициализированный указатель...
Итераторы ведь абстракция указателей? Ну так в pointer-based коде часто бывает нужен "указетль в никуда" AKA 0 или NULL, если в чистом C...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, LaptevVV, Вы писали:
LVV>А гроссмейстеры ж сплошь и рядом играют...
Ну дык всё равно плохо, и только в какой-то хитрой позиции почему-то хорошо. Типа какие-то преимущества пересиливают "общую плохость".
Мы же общий типичный случай обсуждаем, а не какой-то только "гроссмейстеру" доступный.
Опять же в программировании, в отличии от шахмат, "гроссмейстерский" код -- это почти всегда недостаток. Так как хороший код обычно доступен не только "гроссмейстерам"...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>Ну я вот не знаю, как иначе бороться с переаллокацией всего массива целиком.
Ну списки там всякие, мапы с хэшами...
Для FIFO очередей тоже есть варианты...
Ты вот для чего деки используеш? Без них же жили люди как-то?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Erop wrote:
> kan>Так а чем тогда "неициализированный" итератор не устраивает? > kan> > kan>std::vector<Type>::iterator nullIterator; > kan> > Очевидно тем же чем и неинициализированный указатель...
Он неинициализированный в кавычках. Вполне законное значение, соответсвующее null.
А на кой ты некрофилией занялся?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Erop wrote:
>> kan>Так а чем тогда "неициализированный" итератор не устраивает? >> kan> >> kan>std::vector<Type>::iterator nullIterator; >> kan> >> Очевидно тем же чем и неинициализированный указатель... .>Он неинициализированный в кавычках. Вполне законное значение, соответсвующее null.
Нет, он именно неинициализированный.
Разница такая же, как между int*p; и int*p=0;, c той разницей только, что для итератора стандартного вектора второй записи не существует.
Есть кое-какие итераторы, для которых такое сингулярное значение может использоваться для чего-то помимо присваивания несингулярного значения (например, дял потоков ввода), но в общем случае ты с ними ничего сделать не можешь, кроме как присвоить нормальное значение.
jazzer wrote:
> Нет, он именно неинициализированный. > Разница такая же, как между int*p; и int*p=0;, c той разницей только, > что для итератора стандартного вектора второй записи не существует.
Что за бред? iterator — не POD-тип. Там выполняется конструктор без параметров. Посмотри в исходиках, что-ли:
> Есть кое-какие итераторы, для которых такое сингулярное значение может > использоваться для чего-то помимо присваивания несингулярного значения > (например, дял потоков ввода), но в общем случае ты с ними ничего > сделать не можешь, кроме как присвоить нормальное значение.
Абсолютно то же самое, что и с NULL: разыменовывать нельзя, можно сравнивать с другими.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ., Вы писали:
.>Что за бред? iterator — не POD-тип. Там выполняется конструктор без параметров.
какое отношение имеет ПОД к сингулярности итератора?
.>Посмотри в исходиках, что-ли:
Это особенности реализации.
>> Есть кое-какие итераторы, для которых такое сингулярное значение может >> использоваться для чего-то помимо присваивания несингулярного значения >> (например, дял потоков ввода), но в общем случае ты с ними ничего >> сделать не можешь, кроме как присвоить нормальное значение. .>Абсолютно то же самое, что и с NULL: разыменовывать нельзя, можно сравнивать с другими.
нет, сравнивать тоже нельзя, как и в случае с неинициализированным указателем.
сравнивать можно только если это специально оговорено (а для вектора это не оговорено).
Здравствуйте, gid_vvp, Вы писали:
_>Hi All
_>перечислите, на ваш взгляд, основные минусы STL _>принимаются только ответы с аргументацией
Основной минус STL, что все (string, vector, map) хранится в памяти. Можно написать хитрый allocator, но не сможет использовать логическую структуру данных, а просто аллокирует кусок пямяти. К примеру, в вас есть массив данных в файле из 500000 элементов и индеск как map для этих элементов. Одновременно вы работаете с каким-то фрагментом, скажем из 200 элементов. Очевидно, что весь массив одновременно нельзя загружать в память, а нужно элементы подгружать по мере надобности с диска. Как такие данные содержать в стандартном контейнере?
Здравствуйте, shrecher, Вы писали:
S>Основной минус STL, что все (string, vector, map) хранится в памяти. Можно написать хитрый allocator, но не сможет использовать логическую структуру данных, а просто аллокирует кусок пямяти. К примеру, в вас есть массив данных в файле из 500000 элементов и индеск как map для этих элементов. Одновременно вы работаете с каким-то фрагментом, скажем из 200 элементов. Очевидно, что весь массив одновременно нельзя загружать в память, а нужно элементы подгружать по мере надобности с диска. Как такие данные содержать в стандартном контейнере?
Но можно написать свой контейнер который юудет работать со стандартными алгоритмами.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
J>>Ну я вот не знаю, как иначе бороться с переаллокацией всего массива целиком. E>Ну списки там всякие, мапы с хэшами... E>Для FIFO очередей тоже есть варианты...
Стоп, какие мапы с хешами, когда ты хочешь массив массивов?
Или мы уже сменили тему?
E>Ты вот для чего деки используеш? Без них же жили люди как-то?
для того, чтоб не приходилось копировать вектор целиком, когда он вышел за свой capacity.
Вообще, в мире куча разнообразнх структур данных, кроме вектора, те же упомянутые тобой мапы с хешами
Так что твой вопрос про то, как жили, можно и им переадресовать
Здравствуйте, minorlogic, Вы писали:
M>Здравствуйте, shrecher, Вы писали:
S>>Основной минус STL, что все (string, vector, map) хранится в памяти. Можно написать хитрый allocator, но не сможет использовать логическую структуру данных, а просто аллокирует кусок пямяти. К примеру, в вас есть массив данных в файле из 500000 элементов и индеск как map для этих элементов. Одновременно вы работаете с каким-то фрагментом, скажем из 200 элементов. Очевидно, что весь массив одновременно нельзя загружать в память, а нужно элементы подгружать по мере надобности с диска. Как такие данные содержать в стандартном контейнере?
M>Но можно написать свой контейнер который юудет работать со стандартными алгоритмами.
+1.
Такое чувство, что люди воспринимают STL так: "есть штук пять реализованных контейнеров и штук двадцать реализованных алгоритмов, и штук десять реализованных функторов, и не моги этот список расширять!"
Хотя все ровно наоборот: пиши сколько угодно новых алгоритмов, пусть они просто принимают пару итераторов, и все автоматически срастется с любым совместимым контейнером.
И ппиши сколько угодно новых контейнеров, только пусть они предоставляют пару итераторов, и тогда все написанные алгоритмы с ними автоматически заработают.
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, gid_vvp, Вы писали:
_>>Hi All
_>>перечислите, на ваш взгляд, основные минусы STL _>>принимаются только ответы с аргументацией
S>Основной минус STL, что все (string, vector, map) хранится в памяти. Можно написать хитрый allocator, но не сможет использовать логическую структуру данных, а просто аллокирует кусок пямяти. К примеру, в вас есть массив данных в файле из 500000 элементов и индеск как map для этих элементов. Одновременно вы работаете с каким-то фрагментом, скажем из 200 элементов. Очевидно, что весь массив одновременно нельзя загружать в память, а нужно элементы подгружать по мере надобности с диска. Как такие данные содержать в стандартном контейнере?
А зачем их держать в контейнере? Все равно ссылки/указатели на них нельзя будет сохранять, если они в любой момент могут уехать и на их место загрузится что-то еще.
Если тебе нужно просто пройтись по этому фрагменту — ну так загрузи его и предоставь просто пару указателей на начало-конец — все, все алгоритмы заработают автоматом, с обычными указателями.
Основной минус STL — наличие гнусного алгоритма for_each. В отсутствии лямбда-выражений и вложенных функций наличие for_each выглядело бы просто тонким издевательством над языком и поводом для остроумия, но рекомендации к его использованию поступаюшие от гуру заставляют бедных девелоперов кусать себя за хвост и таки всовывать его в свой код. У тех, кому приходится этот код поддерживать, возникает желание укусить девелопера...
Здравствуйте, Vamp, Вы писали:
S>>>>Основной минус STL...
V>Основной минус STL — наличие гнусного алгоритма for_each. В отсутствии лямбда-выражений и вложенных функций наличие for_each выглядело бы просто тонким издевательством над языком и поводом для остроумия, но рекомендации к его использованию поступаюшие от гуру заставляют бедных девелоперов кусать себя за хвост и таки всовывать его в свой код. У тех, кому приходится этот код поддерживать, возникает желание укусить девелопера...
Если у тебя функтор тривиальный — сойдет и boost::lambda/boost::bind (до определенного предела, конечно)
А если нетривиальный — то я бы закусал девелопера, который пишет лямбду на страницу — нетривиальная дурища должна идти в отдельную функцию.
Посмотри на Python, например — там совершенно драконовские ограничения на то, что можно делать внутри лямбды, а что нельзя.
Именно чтоб народ с ума не сходил.
Ну и, само собой, если семантика работы с контейнером не подходит под for_each — надо просто писать цикл и не сходить с ума, благо, цикл точно так же не будет зависеть от контейнера, а только от пары итераторов на что угодно, так что все в рамках концепции, даже если ты к for_each и ближко не подойдешь.
J>Если у тебя функтор тривиальный — сойдет и boost::lambda/boost::bind (до определенного предела, конечно)
Это не СТЛ
J>Ну и, само собой, если семантика работы с контейнером не подходит под for_each — надо просто писать цикл и не сходить с ума,
Да. Но народ, начитавшись Саттера, уверен, что for_each — это обязательно, и цикл вместо for_each не допустим ни в коем случае.
Причем for each, сам по себе, очень полезная вещь, наглядная, четко демонстрирующая намерения... но увы, не поддерживаемая синтаксически.
Например, конструкция типа
foreach Vector::Iterator element in vector {
element.Display(CurrentMonitor);
}
смотрится безусловно лучше, чем
for (Vector::Iterator b = vector.begin(), e = vector.end(); b!=e; ++b)
b->Display(CurrentMonitor);
Но цикл смотрится в миллион раз лучше, чем
std::foreach(vector.begin(), vector.end(), std::bind2nd(CurrentMonitor, std:mem_fun_ref(&ElementType::display)));
/*А здесь еще изволь указать тип элемента!*/
Здравствуйте, minorlogic, Вы писали:
M>Но можно написать свой контейнер который будет работать со стандартными алгоритмами.
Очень сильно сомневаюсь что это возможно по стандарту. Во всяком случае по факту не получится совместимо. Возьмите STLport и поглядите сколько там директорий для различных компиляторов
Здравствуйте, Vamp, Вы писали:
J>>Если у тебя функтор тривиальный — сойдет и boost::lambda/boost::bind (до определенного предела, конечно) V>Это не СТЛ
со следующей версии и bind, и лямбды — это STL
J>>Ну и, само собой, если семантика работы с контейнером не подходит под for_each — надо просто писать цикл и не сходить с ума,
V>Да. Но народ, начитавшись Саттера, уверен, что for_each — это обязательно, и цикл вместо for_each не допустим ни в коем случае.
Ну это уже просто отсутствие здравого смысла
я использую for_each в двух случаях:
1) то, что я хочу сделать, тривиально и записывается _легко читаемым_ bind или лямбда-выражением (буст, ессно)
2) то, что я хочу сделать, нетривиально и может понадобиться еще где-то и несильно зависит от контекста — тогда это функция или функтор, а в for_each — просто ее вызов.
Во всех остальных случаях я юзаю boost::for_each или прямой цикл (если нужно там счетчики поддерживать, или контекст используется в полный рост, и подобное).
V>Причем for each, сам по себе, очень полезная вещь, наглядная, четко демонстрирующая намерения... но увы, не поддерживаемая синтаксически. V>Например, конструкция типа
V>
V>foreach Vector::Iterator element in vector {
V> element.Display(CurrentMonitor);
V>}
V>
тогда уж foreach Vector::value_type& element in vector
в смысле, если foreach, то зачем нам вообще видеть итераторы
Кстати, Boost.Foreach тоже весьма удобная штука.
V>смотрится безусловно лучше, чем
V>
V>for (Vector::Iterator b = vector.begin(), e = vector.end(); b!=e; ++b)
b->Display(CurrentMonitor);
V>
V>Но цикл смотрится в миллион раз лучше, чем
V>
V>std::foreach(vector.begin(), vector.end(), std::bind2nd(CurrentMonitor, std:mem_fun_ref(&ElementType::display)));
V>/*А здесь еще изволь указать тип элемента!*/
V>
+1
да, это ужас и этот ужас уже deprecated в новом стандарте.
А я для связывания вообще макросами пользуюсь — они решают кучу все еще нерешенных проблем.
Здравствуйте, Programador, Вы писали:
P>Здравствуйте, minorlogic, Вы писали:
M>>Но можно написать свой контейнер который будет работать со стандартными алгоритмами. P>Очень сильно сомневаюсь что это возможно по стандарту. Во всяком случае по факту не получится совместимо. Возьмите STLport и поглядите сколько там директорий для различных компиляторов
ты хочешь сказать, что невозможно написать MySuperVector, который предоставит пару begin/end?
Здравствуйте, Mazay, Вы писали:
M>Я не пытаюсь доказать что STL — отстой. Просто хочу восстановить цепочку рассуждений программиста,который пишет велосипед, вместо использовани STL. Не велосипедничают ведь при конкатенации строк.
На начальной стадии развития некоторые велосипедничают
M>А вот к STL как то привыкнуть не могут.
К STL не нужно привыкать, STL нужно понять. После этого, с большой долей вероятности, можно будет предпологать есть ли тот или иной алгоритм в библиотеке. Всё что нужно будет сделать, это найти его название в справке. Это проще, быстрее и надежнее чем писать велосипеды.
M>Но можно написать свой контейнер который юудет работать со стандартными алгоритмами.
И раде чего, ради std::copy, std::find, etc? Тривиальные вещи. Не говоря о том, что они очень generic, т.е. опять ничего не знают о данных котыми управляют, так они еще очень бедные. Я понимаю если бы они вкючали алгоритмы такие как здесьздесь. То что предоставляет STL банальщина, конечно приятно, но зачивать свой контейнер ради стандартного десятка или полутора смыла не вижу.
Здравствуйте, shrecher, Вы писали:
S>И раде чего, ради std::copy, std::find, etc? Тривиальные вещи.
Ни в коем случае. Здесь STL игрет роль интерфейса между контейнерами и алгоритмами. Ктонить пишет алгоритмы и обработчики пользуясь интерфейсом итераторов , ктото свои контейнеры предоставляя итераторы. И после этого они смогут работать вместе не зная ничего друг о друге а только пользуясь концептами предоставленными STL.
Как пример имплементация контейнера хранящего данные во внешней памяти или ДБ.
Здравствуйте, minorlogic, Вы писали:
M>Здравствуйте, shrecher, Вы писали:
S>>И раде чего, ради std::copy, std::find, etc? Тривиальные вещи.
M>Ни в коем случае. Здесь STL игрет роль интерфейса между контейнерами и алгоритмами. Ктонить пишет алгоритмы и обработчики пользуясь интерфейсом итераторов , ктото свои контейнеры предоставляя итераторы. И после этого они смогут работать вместе не зная ничего друг о друге а только пользуясь концептами предоставленными STL.
И к чему такая универсальность? Если есть возможность интеграции на уровне исходного кода, то это будет гораздо произодительнее если разработчики будут знать друг о друге, тем самым создавая более гибкий код.
>Как пример имплементация контейнера хранящего данные во внешней памяти или ДБ.
Отлично! К примеру, реализация Find_if, для VC:
// TEMPLATE FUNCTION find_iftemplate<class _InIt,
class _Pr> inline
_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
{ // find first satisfying _Pred
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Pred);
for (; _First != _Last; ++_First)
if (_Pred(*_First))
break;
return (_First);
}
это простой цикл поиска по условию. Но, где оповещение о прогрессе, где возможность прервать поиск (только не надо _Pred абьюзить он для этого не создан)? Конечно, в общем случае все эти навороты ненужны, но если я буду запускать этот цикл из под UI и поиск идет 5 минут, то это алгоритм не работает — он завесит картинку. Лучше, если при реализации find_if мы будем знать, что прогон цикла дело долгое, и нужно опевещать о процентах выполнения, алгоритм должен быть прерван. Поэтому алгоритм обязан знать о данных с кем он работает. Вот это и беда STL -- слишком универсальный, библиотека не подходит для реальных данных.
Здравствуйте, minorlogic, Вы писали:
M>Здравствуйте, shrecher, Вы писали:
M>Предлагайте альтернативу. А приведенные выше аргументы выглядят странно . "STL не позволяет мне стирать в моей стиральной машине , отстой .."
Тема ведь "минусы STL", вот я вам минусы назвал.Для больщих массивов STL не подходит и нужно всегда помнить сколько вы будите там хранить. Когда проекты разрастаются, то прежде небольшие массивы могут о себе дать знать их нужно из STL-ля выводить.
Плюсы: STL очень хорош для небольших групп данных, алгоритмы удобные в простых случаях, позволяют забыть мелких детаях. Я очень уважаю эту библиотеку
Кстати, еще один небольшой минус — блокирование thread-а контейнера при поиске:
всегда нужно писать так
{
locker()
find( v.begin(), v.end(), a);
}
Нельзя блокировать только часть вектора, списка и пр.
J>со следующей версии и bind, и лямбды — это STL
Будем ждать Интересно, это автоматически выведет за пределы стандарта наш любимый сановский компилятор? И еще интересно, это приведет к тому, что библиотека безнадежно устареет через пару лет, но будучи включенной в стандарт не сможет измениться?
J>тогда уж foreach Vector::value_type& element in vector J>в смысле, если foreach, то зачем нам вообще видеть итераторы
Абсолютно согласен. Видишь, до чего людей СТЛ доводит!
J>Кстати, Boost.Foreach тоже весьма удобная штука.
Я ведь Бюст так и не освоил . Так что остается поверить на слово.
J>да, это ужас и этот ужас уже deprecated в новом стандарте.
В смысле? Депрекейтед в смысле не будет пооджерживаться или в смысле, что будет бюст, который все упростит?
J>А я для связывания вообще макросами пользуюсь — они решают кучу все еще нерешенных проблем.
А какого рода макросы?
Здравствуйте, jazzer, Вы писали:
M>>>Но можно написать свой контейнер который будет работать со стандартными алгоритмами. P>>Очень сильно сомневаюсь что это возможно по стандарту. Во всяком случае по факту не получится совместимо. Возьмите STLport и поглядите сколько там директорий для различных компиляторов
J>ты хочешь сказать, что невозможно написать MySuperVector, который предоставит пару begin/end?
Ваш конечно заработает, там где Вы его напишете. А взять просто взять файл <vector> из одного СТЛ и поместить в другой, здесь у меня сомнения. Хотя и не пробовал
Кстати часто vector выглядит
#include <vector.h>
не очень умно пустое расширение. Не понятно как маску задать. Некоторые поиски по файлам путаются
— здесь 2 текста одного алгоритма, второй из vc2005
Различаются они typedef-ами и в обоих нельзя использовать свой тип итератора. Не получится взять в 32-х разрядной платформе итератор на основе 64-х бит (например для отображения файла) поскольку зашиты в алгоритм глобальные типы, с iterator_traits или без.
V>Основной минус STL — наличие гнусного алгоритма for_each. В отсутствии лямбда-выражений и вложенных функций наличие for_each выглядело бы просто тонким издевательством над языком и поводом для остроумия
Кстати, совсем недавно случайно узнал что MSVC 2005 и старше (2008) замечательно копмилирует вот такое:
Здравствуйте, Pasternak, Вы писали:
P>К STL не нужно привыкать, STL нужно понять. После этого, с большой долей вероятности, можно будет предпологать есть ли тот или иной алгоритм в библиотеке. Всё что нужно будет сделать, это найти его название в справке. Это проще, быстрее и надежнее чем писать велосипеды.
А что значит "понять"? Я вот понять понял, а использовать не рвусь.
Ещё алгоритмы из STL туда сюда. Хотя большинство из них не особо полезные, IMHO. Но контейнеры точно не хочу использовать по любому
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, ., Вы писали:
.>А на кой ты некрофилией занялся?
Да всё равно тему уже дано подняли...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jazzer, Вы писали:
J>Стоп, какие мапы с хешами, когда ты хочешь массив массивов?
В MFL, например, массив массивов иметь не накладно...
Но дека -- это же вроде бы последовательность всё-таки?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
J>>Стоп, какие мапы с хешами, когда ты хочешь массив массивов? E>В MFL, например, массив массивов иметь не накладно... E>Но дека -- это же вроде бы последовательность всё-таки?
ну да. А массив массивов?
Послушай, у меня создается впечатление, что мы говорим о разных вещах.
Можешь уточнить постановку задачи в целом?
Здравствуйте, jazzer, Вы писали:
J>Можешь уточнить постановку задачи в целом?
Зачем так уж сильно нужен контейнер std::deque? Для какой практической задачи?
Для массива массивов удобнее иметь массив, который можно задёшево складывать в массив.
Для FIFO хорошо работает вроде бы циклический буфер.
А для чего очень нужен std::deque? Мне вот вроде бы пока что ни разу не понадобился.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
может показаться, что ваш пример более простой, НО:
— array должен содержать как минимум N элементов и за этим надо постоянно следить. Такой код содержит потенциальные ошибки.
— как показывает практика, программисты очень любят дописывать свою логику в такие циклы. Вот ему надо конкретно сейчас, конкретно здесь что-то сделать, — он, не задумываясь, "вбивает колышек", и со временем цикл превращается в спагетти код.
— использование циклов ведет к дублированию кода. Функторы можно использовать повторно.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, Adriano, Вы писали:
A>>Не согласны?
RO>С поднятием древней малополезной ветки из полугодичного небытия?
Занимаясь разработкой кроссплатформенных приложений, в том числе, для мобильных устройств, все больше склоняюсь к тому, чтобы вовсе отказаться от библиотеки STL. Среди недостатков могу привести следующие:
1) Не очень высокая производительность. Например, низкая скорость сравнения строк в классах string и wstring, обусловленная примененным архитектурным решением — использованием дополнительного класса char_traits для абстрагирования от формата символов. Все символы там сравниваются с помощью функции char_traits::compare, которая, по-идее, должна была бы использоваться как inline-функция, но на практике компилятор по какой-то причине этого не делает (несмотря на соответствующие флаги компиляции). Несложный самодельный класс динамической строки, который может написать программист средней квалификации, достаточно существенно превосходит классы string и wstring по быстродействию и уменьшает объем генерируемого кода. Не очень высокой скоростью работы на практике отличается контейнер map. К тому же, во многих случаях он может быть заменен на более эффективные и достаточно простые решения, учитывающие специфику конкретной задачи. Например, простецкая хэш-таблица строк, которую может написать любой студент, далеко обгоняет map<string, ...>, использует гораздо меньше памяти и генерирует несравнимо меньше кода.
2) Существенное снижение скорости компиляции. В случае с компилятором GCC, который компилирует программы значительно медленнее Visual C++, это может превратиться в кошмар.
3) Существенное увеличение объема исполняемого кода. При интенсивном использовании STL во всем коде программе, исполняемый файл может вырасти до неприличных размеров.
4) Небольшой выбор структур данных, даже с учетом TR1. Дело в том, что такие контейнеры как vector, list, deque, map, set хотя и являются универсальными, достаточно удобными в использовании, но во многих случаях вызывают проблемы с быстродействием из-за своей неэффективной работы с памятью. Во многих случаях вместо них могут быть использованы более специализированные структуры данных. Например, если нам требуется сохранить большое и заранее неизвестное количество элементов небольшого размера, и при этом мы знаем, что нам не потребуется удаление элементов по отдельности и произвольный доступ к элементам по индексу, мы можем использовать односвязный список, каждый элемент которого представляет собой массив из N элементов. Такая структура позволяет перечислять элементы только в одном направлении, и не рассчитана на удаление и вставку элементов, но она проста в реализации и обеспечивает максимальное быстродействие и наилучшее использование памяти в рамках конкретной задачи.
5) Плохой синтаксис и странные идентификаторы. Я слышал от многих программистов удивление по поводу того, почему в STL’е массив называется «vector», а не «array». Еще примеры: «front» и «back» вместо «first» и «last»; «push_back» вместо, например, «add» или «add_item», или «append»; «size» вместо «count» или «items_count»; «erase» вместо «delete» или «remove». Кстати, образцом в этом отношении я считаю библиотеку классов .Net. Кроме того, неудобно то, что итератор сам не может определять конец итерации. Это приводит к более сложной и менее понятной записи, а также повышает вероятность совершения ошибки.
6) Неидеальная портируемость. Дело в том, что некоторые платформы предлагают свои версии STL, которые в некоторых моментах могут отличаться от стандартных реализаций (например, стандартной реализации от Dinkumware), и могут обладать еще более плохими показателями быстродействия.
Здравствуйте, oziro, Вы писали:
O>Здравствуйте, Adriano, Вы писали:
A>>если вы про дату, то я на нее не смотрел
O>А зря, так можно много чего наподнимать. Плиз, в след раз лучше вынести цитату из интересующего поста в новую тему.
Здравствуйте, Аноним, Вы писали:
А>5) Плохой синтаксис и странные идентификаторы. Я слышал от многих программистов удивление по поводу того, почему в STL’е массив называется «vector», а не «array». Еще примеры: «front» и «back» вместо «first» и «last»; «push_back» вместо, например, «add» или «add_item», или «append»; «size» вместо «count» или «items_count»; «erase» вместо «delete» или «remove». Кстати, образцом в этом отношении я считаю библиотеку классов .Net.
Это стеб или нет? Образец — это когда у одних классов размер называется Length, у других — Count?
Re[3]: минусы STL
От:
Аноним
Дата:
28.12.08 18:24
Оценка:
R>Это стеб или нет? Образец — это когда у одних классов размер называется Length, у других — Count?
Что ж поделаешь, нет в мире совершенства. Это, по-моему, чуть ли не единственный ляпсус в этой библиотеке. В целом, филологический уровень библиотеки классов .Net выше, чем у многих других библиотек. Вообще, я считаю, что эта библиотека представляет собой один из лучших стандартных программных интерфейсов на сегодняшний день, если не самый лучший.
Здравствуйте, Аноним, Вы писали:
R>>Это стеб или нет? Образец — это когда у одних классов размер называется Length, у других — Count?
А>Что ж поделаешь, нет в мире совершенства. Это, по-моему, чуть ли не единственный ляпсус в этой библиотеке. В целом, филологический уровень библиотеки классов .Net выше, чем у многих других библиотек.
А>Вообще, я считаю, что эта библиотека представляет собой один из лучших стандартных программных интерфейсов на сегодняшний день, если не самый лучший.
Смотря по каким критериям определять «хорошесть». Как по мне, лучший интерфейс в части контейнеров — итераторы STL и вообще Generic Programming.
Здравствуйте, Аноним, Вы писали:
А>Занимаясь разработкой кроссплатформенных приложений, в том числе, для мобильных устройств, все больше склоняюсь к тому, чтобы вовсе отказаться от библиотеки STL. Среди недостатков могу привести следующие:
STL — это не библиотека, а скорее подход. Ты можешь написать свой контейнер, и он будет совместим со всем остальным кодом в стиле STL. Так что эти недостатки все поправимы.
Здравствуйте, Аноним, Вы писали:
А> если нам требуется сохранить большое и заранее неизвестное количество элементов небольшого размера, и при этом мы знаем, что нам не потребуется удаление элементов по отдельности и произвольный доступ к элементам по индексу, мы можем использовать односвязный список, каждый элемент которого представляет собой массив из N элементов. Такая структура позволяет перечислять элементы только в одном направлении, и не рассчитана на удаление и вставку элементов, но она проста в реализации и обеспечивает максимальное быстродействие и наилучшее использование памяти в рамках конкретной задачи.
Здравствуйте, oziro, Вы писали:
O>Здравствуйте, minorlogic, Вы писали:
M>>Зачем ? в чем преимущество ?
O>Претят большие и старые темы, уж не знаю почему Казалось бы, Янусом не пользуюсь, закачивать тонны не приходится...
Как бы хотелось бы большего конструктива. Когда поднимается старая ветка , под рукой весь контекст беседы.
Здравствуйте, minorlogic, Вы писали:
M>Как бы хотелось бы большего конструктива. Когда поднимается старая ветка , под рукой весь контекст беседы.
Какой может быть конструктив? Мне не нужен контекст, я гляну и в прошлую тему, если в первом сообщении будет указана ссылка "по мотивам". В веб-интерфейсе в деревянном представлении опять же меньше мусора. Ну и просто, как я сказал, мне не удобно. В правилах указано на эту тему что-нибудь? Нет. Так вот я имею сказать, что мне не удобно копаться в старых темах. Будет много возражений, может что и в правила добавят.
Здравствуйте, Аноним, Вы писали:
А>Занимаясь разработкой кроссплатформенных приложений, в том числе, для мобильных устройств, все больше склоняюсь к тому, чтобы вовсе отказаться от библиотеки STL. Среди недостатков могу привести следующие:
Ну, вполне обоснованно, получается что в вашей области STL не применим. Однако, ниже пара советов.
А>2) Существенное снижение скорости компиляции. В случае с компилятором GCC, который компилирует программы значительно медленнее Visual C++, это может превратиться в кошмар.
Попробуйте обновить gcc или использовать precompiled headers. STL не такая уж огромная библиотека, и без её использования вы быстро достигните той же скорости компиляции (особенно если начнёте писать свои контейнеры вместо STL).
А>3) Существенное увеличение объема исполняемого кода. При интенсивном использовании STL во всем коде программе, исполняемый файл может вырасти до неприличных размеров.
Можно попробовать переписать list<T> с наследованием над list<void*> или над list<sizeof T> (то же и с другими контейнерами), частенько встречал такие реализации для слабых платформ.
А>4) .. мы можем использовать односвязный список, каждый элемент которого представляет собой массив из N элементов. Такая структура позволяет перечислять элементы только в одном направлении, и не рассчитана на удаление и вставку элементов, но она проста в реализации и обеспечивает максимальное быстродействие и наилучшее использование памяти в рамках конкретной задачи.
Возможно, использование pooled allocator для list-а даст вам то что вы желаете.
А>5) Плохой синтаксис и странные идентификаторы. Я слышал от многих программистов удивление по поводу того, почему в STL’е массив называется «vector», а не «array». Еще примеры: «front» и «back» вместо «first» и «last»; «push_back» вместо, например, «add» или «add_item», или «append»; «size» вместо «count» или «items_count»; «erase» вместо «delete» или «remove». count переводиться как посчитать, соответственно ожидает на входе "что" (что и реализовано в algorithm). А в общем тут к чему привык первому или на вкус и цвет. Хотя дополнительно могу сказать что мне тоже не нравиться одновременное присутствие методов remove и erase в одном классе (list).
A> Кроме того, неудобно то, что итератор сам не может определять конец итерации. Это приводит к более сложной и менее понятной записи, а также повышает вероятность совершения ошибки.
Это было сделано из соображений эффективности. У STL как у general purpose library — хорошая производительность.
Здравствуйте, <Аноним>, Вы писали:
А>Занимаясь разработкой кроссплатформенных приложений, в том числе, для мобильных устройств, все больше склоняюсь к тому, чтобы вовсе отказаться от библиотеки STL. Среди недостатков могу привести следующие:
А>1) Не очень высокая производительность.
Я вас поправлю. Правильнее было бы написать , "Не очень высокая производительность некоторых имплементаций STL на некоторых операциях" , правильно ?
А>2) Существенное снижение скорости компиляции. В случае с компилятором GCC, который компилирует программы значительно медленнее Visual C++, это может превратиться в кошмар.
Боюсь что это недостаток любой шаблонной библиотеки контейнеров.
А>3) Существенное увеличение объема исполняемого кода. При интенсивном использовании STL во всем коде программе, исполняемый файл может вырасти до неприличных размеров.
Вот это скорее из области мифов , для сравнения нодо бы сравнить аналогичный код с STL и без.
А>4) Небольшой выбор структур данных, даже с учетом TR1.
Я соглашусь что это недоработка на сегодняшний день , зато компенсируется тем что можно писать свои контейнеры совместимые.
А>5) Плохой синтаксис и странные идентификаторы.
Я бы оценил как приемлемый синтаксис. Не идеал на мой взгляд , но для реально использования вполне подходит.
А>6) Неидеальная портируемость. Дело в том, что некоторые платформы предлагают свои версии STL, которые в некоторых моментах могут отличаться от стандартных реализаций (например, стандартной реализации от Dinkumware), и могут обладать еще более плохими показателями быстродействия.
Нукак бы ... это же не проблемы STL ? правда ?
А>>1) Не очень высокая производительность. M>Я вас поправлю. Правильнее было бы написать , "Не очень высокая производительность некоторых имплементаций STL на некоторых операциях" , правильно ?
Я говорил о реальной средней производительности, получаемой при практическом использовании разных реализаций STL.
А>>2) Существенное снижение скорости компиляции. В случае с компилятором GCC, который компилирует программы значительно медленнее Visual C++, это может превратиться в кошмар. M>Боюсь что это недостаток любой шаблонной библиотеки контейнеров.
В том-то и дело, что не любой. Существуют реализации той же самой STL, которые компилируются в несколько раз быстрее за счет значительно более лаконичного кода (но они мне не подходят из-за других параметров).
А>>3) Существенное увеличение объема исполняемого кода. При интенсивном использовании STL во всем коде программе, исполняемый файл может вырасти до неприличных размеров. M>Вот это скорее из области мифов , для сравнения нодо бы сравнить аналогичный код с STL и без.
То, о чем я здесь писал — это не абстрактные рассуждения, а выводы, сделанные исключительно на основе практики. Совсем недавно был пример, когда я ради эксперимента заменил deque на самодельный класс в паре мест программы и получил уменьшение размеров исполняемого файла на 200 kb.
С другой стороны, для тех, кто пишет программы для PC, а не для мобильных устройств, данный показатель не очень важен.
А>>4) Небольшой выбор структур данных, даже с учетом TR1. M>Я соглашусь что это недоработка на сегодняшний день , зато компенсируется тем что можно писать свои контейнеры совместимые.
В том-то и дело, что если уж писать свои контейнеры, то зачем тогда мне этот STL?
А>>5) Плохой синтаксис и странные идентификаторы. M>Я бы оценил как приемлемый синтаксис. Не идеал на мой взгляд , но для реально использования вполне подходит.
Лично мне не нравится синтаксис STL, и от многих программистов я слышал нарекания в его адрес.
А>>6) Неидеальная портируемость. Дело в том, что некоторые платформы предлагают свои версии STL, которые в некоторых моментах могут отличаться от стандартных реализаций (например, стандартной реализации от Dinkumware), и могут обладать еще более плохими показателями быстродействия. M>Нукак бы ... это же не проблемы STL ? правда ?
Да, в общем-то, это не проблемы самой STL, но, опять же, это влияет на вопрос выбора библиотеки на практике.
Здравствуйте, oziro, Вы писали:
O>В правилах указано на эту тему что-нибудь? Нет. Так вот я имею сказать, что мне не удобно копаться в старых темах. Будет много возражений, может что и в правила добавят.
А в правилах есть на эту тему рекомендация. В части "После того, как вопрос задан", пункт 3:
Если вы таки не получили ответа на свой вопрос, не нужно публиковать его заново. Второй топик будет удалён модератором. В таком случае лучше ответьте на своё сообщение сами и в этом сообщении уточните задачу. Это поднимет топик наверх и даст вам ещё один шанс получить ответ.
То, что тема поднята не топикастером, думаю, особого значения не имеет.
--
Re[4]: минусы STL
От:
Аноним
Дата:
29.12.08 10:16
Оценка:
Здравствуйте, Аноним, Вы писали:
А>В том-то и дело, что не любой. Существуют реализации той же самой STL, которые компилируются в несколько раз быстрее
Огласите пожалуйста ссылки на реализации, и если есть, результаты тестов и описание окружения в котором они выполнялись. Без этого ваши утверждения являются голословными. Так же просьба уточнить смысл выражения "реализации STL, которые компилируются". Это компиляция '*.cpp' используемых реализацией или что-то другое?
А>за счет значительно более лаконичного кода (но они мне не подходят из-за [b]других параметров[b]).
Каких ?
А-а-а-а-а!!! Оно опять всплыло!!! Ну сколько можно?
Если по существу вопроса, то:
A>- как показывает практика, программисты очень любят дописывать свою логику в такие циклы. Вот ему надо конкретно сейчас, конкретно здесь что-то сделать, — он, не задумываясь, "вбивает колышек", и со временем цикл превращается в спагетти код.
Моя практика показывает мне, что есть программисты склонные к спагети, а есть, склонные к тому, чтобы вовремя проводить рефакторинг куска кода. IMHO, усложнение испольуемых рументов не помогает первым и мешает вторым
A>- использование циклов ведет к дублированию кода. Функторы можно использовать повторно.
Ну, главное в переиспользуемом коде -- наличие ясной семантики у переиспользуемого куска. А не то, весь это цикл или только функтор. Переиспользование-то не самоцель. Цель -- скорость разработки и дешевизна поддержки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: минусы STL
От:
Аноним
Дата:
02.01.09 13:01
Оценка:
А>>В том-то и дело, что не любой. Существуют реализации той же самой STL, которые компилируются в несколько раз быстрее А>Огласите пожалуйста ссылки на реализации, и если есть, результаты тестов и описание окружения в котором они выполнялись. Без этого ваши утверждения являются голословными.
ustl library — если вы вставите ее в свою программу вместо стандартного STL, очень вероятно, что ваша программа будет компилироваться намного быстрее и генерировать меньше кода.
Тесты я, естественно, не проводил. Как вы правильно заметили, мои утверждения — голословны. Дело в том, что я не пытаюсь идти войной против STL. Мной движет исключительно практический интерес. Я пытаюсь объективно оценить достоинства и недостатки этой библиотеки (или, правильнее говорить, этого стандарта) в применении к моему проекту, чтобы решить, продолжать ли мне использовать ее при разработке новых модулей проекта или нет.
Сейчас я оцениваю преимущества и недостатки библиотеки Boost для использования в моем проекте. Дело в том, что STL — это одно, а STL + Boost — уже совсем другое.
А>Так же просьба уточнить смысл выражения "реализации STL, которые компилируются". Это компиляция '*.cpp' используемых реализацией или что-то другое?
Речь идет о скорости компиляции кода, в котором используется STL.
Re[5]: минусы STL
От:
Аноним
Дата:
02.01.09 13:23
Оценка:
А>>Что ж поделаешь, нет в мире совершенства. Это, по-моему, чуть ли не единственный ляпсус в этой библиотеке. В целом, филологический уровень библиотеки классов .Net выше, чем у многих других библиотек.
RO>С этим тебе в другой флейм: http://rsdn.ru/forum/message/3229054.1.aspx
Здравствуйте, Аноним, Вы писали:
А>5) Плохой синтаксис и странные идентификаторы. Я слышал от многих программистов удивление по поводу того, почему в STL’е массив называется «vector», а не «array». Еще примеры: «front» и «back» вместо «first» и «last»; «push_back» вместо, например, «add» или «add_item», или «append»; «size» вместо «count» или «items_count»; «erase» вместо «delete» или «remove». Кстати, образцом в этом отношении я считаю библиотеку классов .Net. Кроме того, неудобно то, что итератор сам не может определять конец итерации. Это приводит к более сложной и менее понятной записи, а также повышает вероятность совершения ошибки.
Здравствуйте, blackhearted, Вы писали:
B>remove() и erase() — это разные вещи
Очень очень ценное новое и оригинальное замечание, чтобы поднять ветку от 23.08.06...
Некропостеры!!!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
за что хочется послать отдельный луч поноса в комитет, так это за то что stl проектировалась без оглядки на реальные условия в которых находится С++ программист.
возьмем например map<string,foo> в котором мы по строке ищем foo. на бумаге все прекрасно, но что делать когда в качестве ключей в программе не std::string, а сишные строки возвращаемые например функциями ОС? в этом случае map::find будет из сишной строки лепить временную std::string дергая malloc\free. В итоге на ровном месте получаем чудовищное падение производительности из-за того, что в stl не удосужились слепить шаблонный map::find употребляющий произвольный тип ключа.
такой дизайн — откровенная халтура, что впрочем неудивительно для вещей которые пишутся для других, а не для себя.
ближайший пример аналогичной халтуры — mfc, где афторы тупо копипастили виндовый апи и в результате имеется зоопарк из функций ResetContent, DeleteAllItems делающих одно и то же.
Здравствуйте, Kluev, Вы писали:
K>начнем тогда второй круг пожалуй
K>за что хочется послать отдельный луч поноса в комитет, так это за то что stl проектировалась без оглядки на реальные условия в которых находится С++ программист. K>возьмем например map<string,foo> в котором мы по строке ищем foo. на бумаге все прекрасно, но что делать когда в качестве ключей в программе не std::string, а сишные строки возвращаемые например функциями ОС? в этом случае map::find будет из сишной строки лепить временную std::string дергая malloc\free. В итоге на ровном месте получаем чудовищное падение производительности из-за того, что в stl не удосужились слепить шаблонный map::find употребляющий произвольный тип ключа.
Объясни , что тебе мешает сделать ассоциативный массив с ключом сишная строка ?
Здравствуйте, minorlogic, Вы писали:
M>Объясни , что тебе мешает сделать ассоциативный массив с ключом сишная строка ?
Неудобно.
1) Надо писать специальный компоратор.
2) Надо как-то владеть ключами.
Но в целом можно конечно что-нибудь на эту тему соорудить, кто бы спорил. Другое дело, что хрен ли это в стандартной библиотеке не стали делать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, minorlogic, Вы писали:
M>>Объясни , что тебе мешает сделать ассоциативный массив с ключом сишная строка ? E>Неудобно. E>1) Надо писать специальный компоратор. E>2) Надо как-то владеть ключами.
E>Но в целом можно конечно что-нибудь на эту тему соорудить, кто бы спорил. Другое дело, что хрен ли это в стандартной библиотеке не стали делать?
Было бы супер неадекватно делать специализацию , которая со встроенными сишными строками вела себя уникальным образом.
Критикуешь — предлагай!
Здравствуйте, minorlogic, Вы писали:
M>Было бы супер неадекватно делать специализацию , которая со встроенными сишными строками вела себя уникальным образом. M>Критикуешь — предлагай!
Ну, одно из решений -- разрешить сравнивать ключ с любым типом, при помощи шаблонного метода...
Другое, придумать какой-нибудь хитрый тип для ключа, который бы использовался в этом случае.
Но тут есть ещё одна беда. Суть беды состоит в том, что дерево из 0-терминированных строк можно намного лучше упаковать. И можно бы было иметь какой-то map для таких случаев. Или, хотя бы иметь какую-то конструкцию, которую можно было бы позволить авторам реализации специализировать таким способом...
Но это я так, в порядке спонсорской помощи... Я-то свой выбор давно уже сделал
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Но в целом можно конечно что-нибудь на эту тему соорудить, кто бы спорил. Другое дело, что хрен ли это в стандартной библиотеке не стали делать?
Для С-шных строк стоит использовать hash_map, а не tree.
Здравствуйте, minorlogic, Вы писали:
M>Было бы супер неадекватно делать специализацию , которая со встроенными сишными строками вела себя уникальным образом. M>Критикуешь — предлагай!
1) Писать надо в соотвествии с принципом KISS, без извращений и подросткового пафоса
2) Вместо шизы аллокатороров — нормальные интрузивные контейнеры для list/map/hash_map.
3) Методы работающие с ключем — шаблонные и хавают любой совместимый тип.
Это простые и очевидные вещи которые позволяют программировать без дополнительных костылей и извращений неизбежных в случае использования stl
Здравствуйте, Cyberax, Вы писали:
C>Для С-шных строк стоит использовать hash_map, а не tree.
А если и tree, то тогда уж префиксное...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, minorlogic, Вы писали:
M>>Было бы супер неадекватно делать специализацию , которая со встроенными сишными строками вела себя уникальным образом. M>>Критикуешь — предлагай!
K>1) Писать надо в соотвествии с принципом KISS, без извращений и подросткового пафоса K>2) Вместо шизы аллокатороров — нормальные интрузивные контейнеры для list/map/hash_map. K>3) Методы работающие с ключем — шаблонные и хавают любой совместимый тип.
K>Это простые и очевидные вещи которые позволяют программировать без дополнительных костылей и извращений неизбежных в случае использования stl
Вы наверное шутите ? Мы обсуждаем библиотеку для универсального использования а вы приводите конкретный пример и обижаетель "не работает". Вы сами можете написать сравнительный анализ использования интрузивных или неинтрузивных контейнеров для библиотеки "общего назначения" ?
Здравствуйте, minorlogic, Вы писали:
K>>Это простые и очевидные вещи которые позволяют программировать без дополнительных костылей и извращений неизбежных в случае использования stl
M>Вы наверное шутите ? Мы обсуждаем библиотеку для универсального использования а вы приводите конкретный пример и обижаетель "не работает".
а вам этого мало? перечитайте веточку. stl — кривое поделие, источник костылей и воркэраундов в коде. Кроме того она банально неудобная и черезмерно многословная.
M>Вы сами можете написать сравнительный анализ использования интрузивных или неинтрузивных контейнеров для библиотеки "общего назначения" ?
Интрузивные контейнеры гораздо более универсальная вещь нежели stl-like (речь идет естственно о node-based контейнерах). Во первых на базе интрузивных контейнеров можно всегда и без всяких проблем слепить неинтрузивные. Во вторых интрузивный контейнер свободен от необходимости аллоцировать элементы, что дает огромное преимущество. Программист сам аллоцирует обьект как считает нужным и помещает его в контейнер. Например, обькты могут быть созданы статически и затем помещены в контейнер. В контейнерах stl-like такое не сделаешь никаким аллокатором, хотябы в силу того что они расчитаны на копируемые типы и помещение обьекта в контейнер требует аллокаци элемента.
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, minorlogic, Вы писали:
K>>>Это простые и очевидные вещи которые позволяют программировать без дополнительных костылей и извращений неизбежных в случае использования stl
M>>Вы наверное шутите ? Мы обсуждаем библиотеку для универсального использования а вы приводите конкретный пример и обижаетель "не работает".
K>а вам этого мало? перечитайте веточку. stl — кривое поделие, источник костылей и воркэраундов в коде. Кроме того она банально неудобная и черезмерно многословная.
Читал, в основном безграмотность.
M>>Вы сами можете написать сравнительный анализ использования интрузивных или неинтрузивных контейнеров для библиотеки "общего назначения" ?
K>Интрузивные контейнеры гораздо более универсальная вещь нежели stl-like (речь идет естственно о node-based контейнерах). Во первых на базе интрузивных контейнеров можно всегда и без всяких проблем слепить неинтрузивные.
Вы представляете себе каждый раз оборачивать std::vector<int> в неинтрузивную обертку ? Может еще раз подумать зачем контейнеры "общего назначения" неинтрузивные?
K> Во вторых интрузивный контейнер свободен от необходимости аллоцировать элементы, что дает огромное преимущество. Программист сам аллоцирует обьект как считает нужным и помещает его в контейнер. Например, обькты могут быть созданы статически и затем помещены в контейнер. В контейнерах stl-like такое не сделаешь никаким аллокатором, хотябы в силу того что они расчитаны на копируемые типы и помещение обьекта в контейнер требует аллокаци элемента.
В общем случае это видимо ОЧЕНЬ удобно, отделить время жизни объекта входящего в контейнер от времени жизни контейнера.
Здравствуйте, Kluev, Вы писали:
K>... В контейнерах stl-like такое не сделаешь никаким аллокатором, хотябы в силу того что они расчитаны на копируемые типы и помещение обьекта в контейнер требует аллокаци элемента.
Можно поместить указатели, на статические данные, например...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, minorlogic, Вы писали:
M>>>Вы наверное шутите ? Мы обсуждаем библиотеку для универсального использования а вы приводите конкретный пример и обижаетель "не работает".
K>>а вам этого мало? перечитайте веточку. stl — кривое поделие, источник костылей и воркэраундов в коде. Кроме того она банально неудобная и черезмерно многословная. M>Читал, в основном безграмотность.
да, а stl вся такая удобная и пушистая. смешно.
M>>>Вы сами можете написать сравнительный анализ использования интрузивных или неинтрузивных контейнеров для библиотеки "общего назначения" ?
K>>Интрузивные контейнеры гораздо более универсальная вещь нежели stl-like (речь идет естственно о node-based контейнерах). Во первых на базе интрузивных контейнеров можно всегда и без всяких проблем слепить неинтрузивные. M>Вы представляете себе каждый раз оборачивать std::vector<int> в неинтрузивную обертку ? Может еще раз подумать зачем контейнеры "общего назначения" неинтрузивные?
ты чтоже читать не умеешь? K>>речь идет естственно о node-based контейнерах
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Kluev, Вы писали:
K>>... В контейнерах stl-like такое не сделаешь никаким аллокатором, хотябы в силу того что они расчитаны на копируемые типы и помещение обьекта в контейнер требует аллокаци элемента.
E>Можно поместить указатели, на статические данные, например...
Здравствуйте, Kluev, Вы писали:
M>>Читал, в основном безграмотность. K>да, а stl вся такая удобная и пушистая. смешно.
Не пушистая, а требует достаточно высокой квалификации.
K>ты чтоже читать не умеешь? K>>>речь идет естственно о node-based контейнерах
Т.е. для node-based одно время жизни , для других другое ? Очень удобно ...
Здравствуйте, minorlogic, Вы писали:
M>Не пушистая, а требует достаточно высокой квалификации.
IMHO, это недостаток...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, minorlogic, Вы писали:
M>Здравствуйте, Kluev, Вы писали:
M>>>Читал, в основном безграмотность. K>>да, а stl вся такая удобная и пушистая. смешно. M>Не пушистая, а требует достаточно высокой квалификации.
... требует достаточно высокой квалификации для написания костылей и воркэраундов
K>>ты чтоже читать не умеешь? K>>>>речь идет естственно о node-based контейнерах
M>Т.е. для node-based одно время жизни , для других другое ? Очень удобно ...
из других остаются только вектора, а разница м-ду векторами и node-based контейнерами (особенно инструзивными) настолько существенная, что глупо пытатся их ровнять под одну гребенку. к тому же вектор это очень спорный контейнер, я уже не помню когда использовал его последний раз именно как контейнер. только для временных данных или для вычислительных вещей. для всего остального исключительно списки.
Здравствуйте, Kluev, Вы писали:
K>можно, но указатели тоже нужно где-то хранить.
Ну и указатели на ноды тоже нужно хранить... оверхед получится в указатель на элемент. Если элемент большой, то и не очень страшно, а если маленький, то и копировать его можно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском