Re[3]: минусы STL - нетранзакционность
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 07.09.06 08:41
Оценка:
Здравствуйте, Evgeniy13, Вы писали:

E>у нас в проекте во многих местах есть проверки, что malloc вернет ноль — это лишь откладывает ошибку на некоторое (не такое уж и большое время), а если разрабатывать суперстабильную систему, то все равно нужно как-то обрабатывать подобные исключительные ситуации (тогда какая разница: поймать исключение или проверить результат функции?)... а может вообще vector, например, должен _молча_ выделить столько, сколько сможет и все?!


Насчет разницы.
Возвращаемое значение легче увидеть в коде, особенно если делать последовательно все функции с возвратом ошибок. В С это делается автоматически, так как возвращаемое значение плюс возможно что-то вроде errno, это практически единственный механизм обработки ошибок, не считая экзотического setjmp, который я видел только в одном Open Source проекте (http://www.lua.org/pil/24.3.html).
Игнорирование возвращаемого значения легко заметить с помощью ключа -Wall и т.п.

При использовании исключений это менее заметно, отчасти из-за отсутсвия диагностики. А замечать это нужно, так как выбрасывание исключений (впрочем, как и преждевременный возврат из функции по ошибке), может легко нарушить инварианты.

Например, при использовании возвращаемого значения часто забывают освободить ранее выделенный в этой функции ресурс. С++ эту проблему решает с помощью RAII. Но к сожалению, она не все случаи охватывает. Типичный пример, это последовательное добавление элемента в различные контейнеры внутри одного объекта. Кто-нибудь делает откат, вызывая pop/pop_front/pop_back после выбрасывания исключений? Некоторые используют ScopeGuard и это хорошо, но он тоже не все случаи покрывает.

Я сделал следующий шаг в этом направлении, но к сожалению, ему нужен typeof:
http://archives.free.net.ph/message/20051110.143747.7119b2ca.en.html
Re[4]: Проблемы STL-контейнеров
От: Константин Л. Франция  
Дата: 07.09.06 08:55
Оценка: :)
Здравствуйте, Пётр Седов, Вы писали:

[]

А>>>10.4. Конкатенация строк обозначается знаком '+'. Ещё одна программистская традиция, идущая вразрез с математикой. В MFC (и много где ещё) то же самое. В Visual Basic-е для этого используется '&', в script-овом языке Lua — '..' (две точки).

А>>>Вместо бинарного operator+, сцепляющего строки по очереди, было бы оптимальнее (по скорости работы программы) использовать функцию Concat, сцепляющую несколько строк одним махом. К счастью, такую функцию (точнее, семейство функций) можно сделать самому. Например:
RO>>Здесь более в духе STL было бы что-то вроде join_iterator. Тоже можно самому написать.
ПС>Итератор нужен для доступа к последовательности. Вы какую последовательность имели в виду? Я имел в виду, что вместо:
ПС>
ПС>DirPath + "\\" + FileName
ПС>

ПС>было бы оптимальнее писать:
ПС>
ПС>Concat(DirPath, "\\", FileName)
ПС>


чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло.

ПС>Насколько я знаю, компилятор C# делает такую замену автоматически.
Re[5]: Проблемы STL-контейнеров
От: Kluev  
Дата: 07.09.06 09:11
Оценка: -1
Здравствуйте, 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) программу неудобно отлаживать, т.к. итератор ничего не говорит ни о номере итерации, ни о индексе элемента в массиве.
Re[6]: Проблемы STL-контейнеров
От: kan Великобритания  
Дата: 07.09.06 11:04
Оценка: +4 :)
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
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: минусы STL
От: gid_vvp  
Дата: 07.09.06 14:03
Оценка: :)
_>>К сожалению это не STL...

A>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html


Это ещё не STL

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Проблемы STL-контейнеров
От: Roman Odaisky Украина  
Дата: 07.09.06 17:08
Оценка:
Здравствуйте, kan, Вы писали:

>> DirPath + "\\" + FileName

>>
>> было бы оптимальнее писать:
>>
>> Concat(DirPath, "\\", FileName)
kan>Но в С++ нет функций с переменным числом аргументов (ellipsis не считается).

будут
Автор: night beast
Дата: 17.08.06
До последнего не верил в пирамиду Лебедева.
Re[5]: минусы STL
От: Шахтер Интернет  
Дата: 07.09.06 21:34
Оценка: +1
Здравствуйте, kan_izh, Вы писали:

_>Шахтер wrote:


>> Ш>>3) Контейнеры. Все STL контейнеры расчитаны на копирабельные типы.

>> Это огромный минус.
>>
>> _>это элементарно обходится: используй контейнеры на SmartPtr, а сам
>> указатель может быть и некопирабельным.
>>
>>
>> И аллокировать каждый объект в динамической памяти?
>> Нет, спасибо.
_>А как ты тогда себе представляешь динамический массив без возможности скопировать элемент?

Я его не представляю. Я его использую.

_>Вроде только если будут move constructor... это обещают в следующей версии языка... но...


Да не нужна новая версия языка для этого. Всё прекрасно можно сделать на старой.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Проблемы STL-контейнеров
От: Пётр Седов Россия  
Дата: 07.09.06 21:45
Оценка: +1 :)
Здравствуйте, 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
}
Пётр Седов (ушёл с RSDN)
Re[5]: Конкатенация строк
От: Пётр Седов Россия  
Дата: 07.09.06 23:58
Оценка:
Здравствуйте, Константин Л., Вы писали:
А>>>>10.4. Конкатенация строк
ПС>>Я имел в виду, что вместо:
ПС>>
ПС>>DirPath + "\\" + FileName
ПС>>

ПС>>было бы оптимальнее писать:
ПС>>
ПС>>Concat(DirPath, "\\", FileName)
ПС>>

КЛ>чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло.
operator+ бинарный. Поэтому в первом варианте сцепление строк делается в два этапа, примерно так:
string Temp = DirPath + "\\";
string Result = Temp + FileName;

То есть сколько плюсов, столько и вызовов. При этом создаются временные буферы (в данном случае один). До последнего operator+ char-ы хранятся во временных буферах. Только последний operator+ создаёт результирующий буфер и копирует туда char-ы.
Функция Concat, в идеале, "сколько-угодно-арная". В моей реализации (здесь
Автор:
Дата: 06.09.06
) используется класс StringBuf. При REALISTIC_STL_IMPL Concat не создаёт временных буферов, а сразу же создаёт результирующий буфер и копирует туда все char-ы.
Пётр Седов (ушёл с RSDN)
Re[5]: Проблемы STL-контейнеров
От: Пётр Седов Россия  
Дата: 08.09.06 03:20
Оценка: :)
Здравствуйте, kan, Вы писали:

kan>Пётр Седов wrote:


>> NULL-итератор

>> То, что для пустого vector-а эти два итератора равны, проблем создавать
>> не должно.
>> Можно использовать boost::optional<iterator>, но лучше не усложнять.
kan>Не понял, а чем std::vector<X>::const_iterator() не устраивает?

>> Я предупредил начинающих, что под 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 (для ВычМата, с расчётом на аппаратное ускорение)
Так когда-то и планировалось (я привёл историческую справку здесь
Автор:
Дата: 06.09.06
).

>> DirPath + "\\" + FileName

>> было бы оптимальнее писать:
>> Concat(DirPath, "\\", FileName)
kan>Но в С++ нет функций с переменным числом аргументов (ellipsis не считается). И ради одной только операции конкатенации вводить такую штуку?..
Я сделал Concat-ы до 5-ти строк:
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);
}

string Concat(ConcatString s1, ConcatString s2, ConcatString s3, ConcatString s4)
{
  const ConcatString Strings[] = { s1, s2, s3, s4 };
  return DoConcat(Strings, 4);
}

string Concat(ConcatString s1, ConcatString s2, ConcatString s3, ConcatString s4, ConcatString s5)
{
  const ConcatString Strings[] = { s1, s2, s3, s4, s5 };
  return DoConcat(Strings, 5);
}

Пока хватало. Не хватит — допишу.

>> Насколько я знаю, компилятор C# делает такую замену автоматически.

kan>Хаки? Или как там это работает?
Там тип string встроен в язык. Например, здесь
Автор: VladD2
Дата: 21.05.05
.
Пётр Седов (ушёл с RSDN)
Re[6]: Проблемы STL-контейнеров
От: night beast СССР  
Дата: 08.09.06 04:11
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

kan>>Но в С++ нет функций с переменным числом аргументов (ellipsis не считается).


RO>будут
Автор: night beast
Дата: 17.08.06


сейчас в comp.std.c++ обсуждают
Re[7]: Проблемы STL-контейнеров
От: Kluev  
Дата: 08.09.06 09:08
Оценка: 1 (1) -3
Здравствуйте, 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 контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.
Re[6]: Конкатенация строк
От: Константин Л. Франция  
Дата: 08.09.06 09:45
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

ПС>Здравствуйте, Константин Л., Вы писали:

А>>>>>10.4. Конкатенация строк
ПС>>>Я имел в виду, что вместо:
ПС>>>
ПС>>>DirPath + "\\" + FileName
ПС>>>

ПС>>>было бы оптимальнее писать:
ПС>>>
ПС>>>Concat(DirPath, "\\", FileName)
ПС>>>

КЛ>>чем оптимальнее? и тут и там идет вызов функции, просто одна из них это operator+. Кроме того, такой Concat можно реализовать только через ellipsis, которые есть зло.
ПС>operator+ бинарный. Поэтому в первом варианте сцепление строк делается в два этапа, примерно так:
ПС>
ПС>string Temp = DirPath + "\\";
ПС>string Result = Temp + FileName;
ПС>

ПС>То есть сколько плюсов, столько и вызовов. При этом создаются временные буферы (в данном случае один). До последнего operator+ char-ы хранятся во временных буферах. Только последний operator+ создаёт результирующий буфер и копирует туда char-ы.
ПС>Функция Concat, в идеале, "сколько-угодно-арная". В моей реализации (здесь
Автор:
Дата: 06.09.06
) используется класс StringBuf. При REALISTIC_STL_IMPL Concat не создаёт временных буферов, а сразу же создаёт результирующий буфер и копирует туда все char-ы.


это все понятно, только вот это временные буферы меня не смущают, в отличие от ваших (вполне пригодных) велосипедов
Re[8]: Проблемы STL-контейнеров
От: Юнусов Булат Россия  
Дата: 08.09.06 10:07
Оценка:
Здравствуйте, Kluev, Вы писали:

kan>>В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".


K>Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — лучше юзать индексы, для интрузивных node-based контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.


Ты себе представляешь stl без итераторов?
Re[9]: Проблемы STL-контейнеров
От: Kluev  
Дата: 08.09.06 12:09
Оценка: 1 (1) -2
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ>Здравствуйте, Kluev, Вы писали:


kan>>>В общем, какие-то надуманные проблемы, чаще всего возникающие от недопонимания понятия "итератор".


K>>Итераторы — это костыли и грабли под видом красивой идеи. Для массивов — лучше юзать индексы, для интрузивных node-based контейнеров достаточно знать указатель на элемент. Лишние сущности не нужны.


ЮБ>Ты себе представляешь stl без итераторов?


Цель итераторов — сделать перебор элементов в разных контейнерах одинаковым. Это больная идея т.к. контейнеры должны перебиратся наиболее нативным для них способом. Как например должен выглядеть итератор для многомерных массивов, кольцевых списков и деревьев? Многие контейнеры в концепцию итераторов просто не вписываются в результате чего программист вынужден пользоватся тем убогим набором который есть в stl. К томуже алгоритмы применимы не ко всем контейнерам и фактически единственным универсальным алгоритмом который подходит для всех является for_each. Но для этого существует более универсальный и могучий паттерн — визитор, который:

1) гораздо проще в реализации чем итератор
2) программы с его использованием получаются более элегантными

сравни
for_each(container.begin(), container.end(), clear_func);
container.clear();

и
container.clear(clear_func);


Третье преимущество в том что внутри 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;
   // .....
}
Re[8]: Проблемы STL-контейнеров
От: kan Великобритания  
Дата: 08.09.06 12:12
Оценка: +2
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
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: Проблемы STL-контейнеров
От: kan Великобритания  
Дата: 08.09.06 12:37
Оценка:
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
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Проблемы STL-контейнеров
От: Kluev  
Дата: 08.09.06 13:14
Оценка: +1 -1 :))
Здравствуйте, 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 основывается на некоторых теоретических аспектах, а не только на общеизвестных практических приёмчиках.

Ты маркетолог или программист? Мне совершенно безразлично на чем основывается стл, главное то что она неюзабельная. Я пользователь библиотеки и меня интересуют в первую очередь удобство использования, отладки и другие прикладные аспекты, а не красивые идеи.
Re[11]: Проблемы STL-контейнеров
От: Kluev  
Дата: 08.09.06 13:49
Оценка: 1 (1) +1 -1
Здравствуйте, 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>для него создать ещё один тип итератора, который будет замыкаться.

Это как? На каждой итерации проверять не в конце ли мы и если в конце то переходить на первый элемент? Значит ради идей уже пожертвовали удобством и отладкой, а теперь вот еще и на производительность плевать. Не самая лучшая идея. Более того такое решение все равно будет более неудобным чем специализированный контейнер.
Re[10]: std::deque<...>::iterator
От: Roman Odaisky Украина  
Дата: 08.09.06 15:36
Оценка:
Предлагаю реализовать аналог std::deque без итераторов.
До последнего не верил в пирамиду Лебедева.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.