Вот очень простая нетехническая причина: это не требуется по стандарту, и любые будущие изменения без всякой причины нарушат обратную совместимость с существующим скомпилированным кодом.
Вернем время назад к началу 2000-х, во время перехода между GCC и GCC 3, а затем, во время незначительных изменений GCC 3. Многие из проектов, над которыми я работал, должны были быть бинарно-совместимыми; мы не могли потребовать от пользователя перекомпилировать наши программы или плагины, а также мы не могли быть уверены в версии GCC, на которой они были скомпилированы, или версии STL, с которой они были скомпилированы.
Решение: не используйте STL. У нас были собственные строки, векторы и попытки, а не использование STL. Решение ада зависимостей, созданное якобы стандартной частью языка, было настолько отличным, что мы отказались от него. И не только в одном или двух проектах.
К счастью, эта проблема в значительной степени ушла, и такие библиотеки, как boost, включили только версии контейнеров STL. В GCC 4 я не вижу проблем с использованием стандартных контейнеров STL, и действительно, бинарная совместимость намного проще, в основном благодаря усилиям по стандартизации.
Но ваше изменение повлечет за собой новую, невысказанную зависимость
Предположим, что завтра появится новая структура данных, которая существенно превосходит красно-черные деревья, но не гарантирует наличие некоторых специализированных итераторов. Одной из таких реализаций, которая была очень популярна всего несколько лет назад, была список пропусков, который предлагал те же гарантии при, возможно, значительно меньшем объеме памяти. Список пропусков, похоже, не сработал, но другая структура данных вполне могла это сделать. Лично я предпочитаю использовать попытки, которые предлагают значительно лучшую производительность кэша и более надежную алгоритмическую производительность; их итераторы будут существенно отличаться от красно-черных деревьев, если кто-то в libstdc++ решит, что эти структуры обеспечивают лучшую общую производительность для большинства применений.
Строго следуя стандарту, обратная бинарная совместимость может поддерживаться даже при изменении структуры данных. Это хорошая вещь (TM) для библиотеки, предназначенной для динамического использования. Я бы и глазом не моргнул, если бы такая оптимизация была хорошо реализована и хорошо использовалась, если бы она использовалась статически, например, библиотека Boost Container.
Но для такой динамической библиотеки, как libstdc++, гораздо важнее обратная бинарная совместимость.
08.01.2014
between
для итераторов дерева? (И как он используется для реализации бинарного поиска? Это просто заменаdistance
+advance
?) 06.01.2014log(distance(begin, end))
). 06.01.2014between
быстрее, чемdistance
+advance
амортизированное, что должно быть легко в шкале нотацииO
для сбалансированного двоичного двунаправленного итерируемого дерева. В идеале вы должны имитировать порядок поискаset::lower_bound
. Дело в том, что иногдаbetween
намного быстрее, чемadvance
, так какadvance
говорит, что я хочу продвинуться ровно столько, когда все, что мы хотим сделать, это продвинуться примерно на полпути кend
. (Обратите внимание, что если бы дерево было быстро индексируемым (скажем, каждый узел отслеживал количество дочерних элементов), можно было бы реализовать логарифмическую скоростьadvance
) 06.01.2014lower_bound
сSkipableIterator
s все еще асимптотически медленнее, чемset::find
, что-то вроде O(logN * logN), так как каждый шаг в двоичном поиске требуетbetween
, что составляет O(logN) (что N уменьшается вдвое). для каждого шага, но асимптотически это не имеет значения). Это лучше, чемlower_bound
с O(N)advance
, но все равно не сделает функцию-член устаревшей. Или вы имели в виду другой алгоритм? 07.01.2014advance
было побочным, я не ожидал, чтоbetween
будет реализовано:between
явно не волнует, где именно он заканчивается, в то время какadvance
, возможно, придется спуститься вниз по дереву, чтобы найти точную место оно хочет быть) 07.01.2014