Счетчик цикла, итераторы
От: Аноним  
Дата: 21.02.12 18:59
Оценка: :))
Приветствую.

— Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет использоваться в качестве индексации масива / контейнера, зачастую используется знаковая целочисленная переменная?

Нет, ну я понимаю, что size_t многим просто не нужен — пишу себе под 32 бита и буду писать, думают они.

А вот почему бы не написать unsigned int, к примеру — ума не приложу. Лень написать лишние буквы?

— Кстати, как часто, когда вы имеете дело с контейнерами, вы используете итераторы? Оператор индексации / метод at настолько же часто?

— Допустим, нам надо выделить два одинаковых по размеру куска памяти одного и того же типа.

Использовали бы стандартный вариант

int *a = new int [n];
int *b = new int [n];



или

int *a = new int [n * 2];
int *b = a + n;


вот такой?
Re: Счетчик цикла, итераторы
От: _niko_ Россия  
Дата: 21.02.12 19:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>- Допустим, нам надо выделить два одинаковых по размеру куска памяти одного и того же типа.


А>Использовали бы стандартный вариант


А>
А>int *a = new int [n];
А>int *b = new int [n];
А>



А>или


А>
А>int *a = new int [n * 2];
А>int *b = a + n;
А>


А>вот такой?


ни тот ни другой, стандартный вариант с динамикой ну ни как не связан:

  std::vector<int> a(n);
  std::vector<int> b(n);
Re: Счетчик цикла, итераторы
От: Сыроежка  
Дата: 21.02.12 19:41
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приветствую.


А>- Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет использоваться в качестве индексации масива / контейнера, зачастую используется знаковая целочисленная переменная?


А>Нет, ну я понимаю, что size_t многим просто не нужен — пишу себе под 32 бита и буду писать, думают они.


А>А вот почему бы не написать unsigned int, к примеру — ума не приложу. Лень написать лишние буквы?


Здесь есть несколько факторов, которые влияют на это решение.
Во-первых, исторически так сложилось, что использовали тип int для счетчиков циклов, так как в С еще не существовало типа unsigned int. Этот тип появился позднее.
Во-вторых, есть некоторое противоречие. Дело в том, что разность между указателямми и итераторами, которую определяют, как имеющую тип difference_type, выражают через знаковый целочисленный тип, например, используют стандартный тип std::ptrdiff_t. В чем заключается противоречие? С одной стороны, обычно для всех контейнеров задают тип size_type как беззнаковый целочисленный тип. С другой стороны, разность между двумя указателями на элементы контейнера, которая как раз и определяет индекс элемента, задается как difference_type, то есть знаковый тип. То есть имеет место быть, что если n — это size_type, то есть беззанковый, то разность между элементами контейнера с прямым доступом, для которого память выделяется одним экстентом, &a[n] — &a[0] в общем случае не равна n. То есть в первом выражении мы получаем знаковое значение, а во втором беззнаковое, а знаковое не может представить в себе все значения беззнакового. Имеет место явное противоречие.

Это противоречие наглядно проявляется в объявление стандартных алгоритмов. Например, посмотрите объявление алгоритма count

template<class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last, const T& value);

С одной стороны вы его можете вызвать для массива, указав диапазон, как, [a, a + N), где N — это беззнаковое целое, как, например, size_t. А на выходе из вызова алгоритма вы получите уж знаковое значение, как, например, int.
Вот, чтобы избежать такого противоречия, программисты часто и используют знаковый тип в циклах.


А>- Кстати, как часто, когда вы имеете дело с контейнерами, вы используете итераторы? Оператор индексации / метод at настолько же часто?


А>- Допустим, нам надо выделить два одинаковых по размеру куска памяти одного и того же типа.


А>Использовали бы стандартный вариант


А>
А>int *a = new int [n];
А>int *b = new int [n];
А>



А>или


А>
А>int *a = new int [n * 2];
А>int *b = a + n;
А>


А>вот такой?


Это плохой способ выделения памяти, так как кто-то может попытаться удалить указатель b, который не указывает на начало выделенной памяти, а потому это может привести к аварийному завершению программы. Так можно делать лишь в том случае, если вы самостоятельно разррабатываете системы выделения памяти для своей программы и, соответственно перегружаете операторы delete и delete[].
Меня можно встретить на www.cpp.forum24.ru
Re: Счетчик цикла, итераторы
От: MasterZiv СССР  
Дата: 21.02.12 19:57
Оценка:
On 02/21/2012 10:59 PM, Аноним 226 wrote:

> — Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет

> использоваться в качестве индексации масива / контейнера, зачастую используется
> знаковая целочисленная переменная?

Меня тоже. Поэтому использую всегда беззнаковые.

> — Кстати, как часто, когда вы имеете дело с контейнерами, вы используете

> итераторы? Оператор индексации / метод at настолько же часто?

Всегда почти при итерации. Всегда при работе алгоритмов.
индексацию можно применять только если это -- контейнес с произвольным доступом.

> — Допустим, нам надо выделить два одинаковых по размеру куска памяти одного и

> того же типа.
>
> Использовали бы стандартный вариант
>
> int *a =new int [n];
> int *b =new int [n];

Да, потому что не факт, что у них будет одинаковое время жизни (т.е. что их
удалять в одно и то же время).
Если будет, то надо делать из них структуру или массив.
Posted via RSDN NNTP Server 2.1 beta
Re: Счетчик цикла, итераторы
От: Панда Россия  
Дата: 21.02.12 20:01
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А вот почему бы не написать unsigned int, к примеру — ума не приложу. Лень написать лишние буквы?


А зачем? Если разницы никакой — то да, лень.
А задачи, где разница есть, встречаются настолько редко, что далеко не каждому программисту хоть раз в жизни попадется.
Re: Счетчик цикла, итераторы
От: Панда Россия  
Дата: 21.02.12 20:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>- Кстати, как часто, когда вы имеете дело с контейнерами, вы используете итераторы? Оператор индексации / метод at настолько же часто?


Если можно индексом, то всегда перебираю индексом. Так короче писать.
Re: Счетчик цикла, итераторы
От: B0FEE664  
Дата: 22.02.12 00:10
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>А вот почему бы не написать unsigned int, к примеру — ума не приложу. Лень написать лишние буквы?


Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.
И каждый день — без права на ошибку...
Re[2]: Счетчик цикла, итераторы
От: Сыроежка  
Дата: 22.02.12 00:15
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Аноним, Вы писали:


А>>А вот почему бы не написать unsigned int, к примеру — ума не приложу. Лень написать лишние буквы?


BFE>Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.


Это так сложно?!

const size_t N;
int a[N];

size_t n = N;
while ( n-- ) a[n] = n;
Меня можно встретить на www.cpp.forum24.ru
Re: Счетчик цикла, итераторы
От: rg45 СССР  
Дата: 22.02.12 01:52
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>- Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет использоваться в качестве индексации масива / контейнера, зачастую используется знаковая целочисленная переменная?


Если говорить о встроенной операции индексирования вообще, то согласно стандарту она сводится к сложению указателя с целым числом и последующим разыменованием. И точно так же, как и операция сложения указателя с целым числом, операция индексирования обладает свойством коммутативности. Так, для любых массива array и целочисленного индекса index следующие выражения являются эквивалентными:

*(array + index)
*(index + array)
array[index]
index[array]

И точно так же, как и операция сложения указателя с целым числом, операция индексирования не накладывает никаких ограничений на знак целочисленного индекса. Т.о. само по себе использование индексирования вовсе не означает, что индекс обязан быть положительным и беззнаковым. Во многих случаях в качестве индексов действительно лучше использовать беззнаковые величины, но, во-первых, не абсолютно всегда, а, во-вторых, по иным соображениям, не связанным с использованием операции индексирования как таковой.
--
Справедливость выше закона. А человечность выше справедливости.
Re: Счетчик цикла, итераторы
От: nen777w  
Дата: 22.02.12 07:02
Оценка:
Всегда пишу unsigned int, ну т.е. не прям всегда, но когда переменная цикла служит только индесатором.
Re[2]: Счетчик цикла, итераторы
От: Centaur Россия  
Дата: 22.02.12 07:23
Оценка: 8 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.


Стандартная идиома:

for (unsigned i = n; i --> 0 ;)
    std::cout << i << std::endl;
Re[3]: Счетчик цикла, итераторы
От: B0FEE664  
Дата: 22.02.12 07:53
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>Это так сложно?!

С>
С>const size_t N;
С>int a[N];
С>size_t n = N;
С>while ( n-- ) a[n] = n;
С>


Так можно. Но это не цикл for, который был бы естественен здесь.
И каждый день — без права на ошибку...
Re[3]: Счетчик цикла, итераторы
От: B0FEE664  
Дата: 22.02.12 07:54
Оценка:
Здравствуйте, Centaur, Вы писали:

BFE>>Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.

C>Стандартная идиома:

C>
C>for (unsigned i = n; i --> 0 ;)
C>    std::cout << i << std::endl;
C>

Стандартная? А где массив?
И каждый день — без права на ошибку...
Re[4]: Счетчик цикла, итераторы
От: Сыроежка  
Дата: 22.02.12 08:10
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Сыроежка, Вы писали:


С>>Это так сложно?!

С>>
С>>const size_t N;
С>>int a[N];
С>>size_t n = N;
С>>while ( n-- ) a[n] = n;
С>>


BFE>Так можно. Но это не цикл for, который был бы естественен здесь.


Это что-то на вас сегодня погода плохо действует. На самом деле имеет место законченное предложение for. Я, кстати сказать, когда написал while, подумал, а почему я не использовал for? Да исправить не знал как.

Итак, мы имеем


size_t n = N;
while ( n-- ) a[n] = n;


Все подготовлено для for. Поэтому пишем


for ( size_t n = N; n--; ) a[n] = n;
Меня можно встретить на www.cpp.forum24.ru
Re[5]: Счетчик цикла, итераторы
От: Erop Россия  
Дата: 22.02.12 08:42
Оценка: +1
Здравствуйте, Сыроежка, Вы писали:

С>Все подготовлено для for. Поэтому пишем



С>
С>for ( size_t n = N; n--; ) a[n] = n;
С>


Это неправильный for! Правильный должен иметь такую сруктуру
for( инициализация; проверка условия; сдвиг итератора )


Но, на самом деле, гемор начинается чуть позже, когда тебе надо поитерировать массив с конца и с шагом step.

Все проблемы лечатся, конечно, кодом вроде такого:
for( unsigned int i = N - 1; i < N; i -= STEP )
но я бы не назвал его интуитивно понятным...
Второй минус такого подхода -- он на итераторы не обобщается, но в итераторах и не надо ходить вниз, с другой стороны.

Но я вообще противник использования беззнаковых целых, без крайней на то нужды. Слишком легко допустить переполнение...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Счетчик цикла, итераторы
От: Centaur Россия  
Дата: 22.02.12 08:46
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.

C>>Стандартная идиома:

C>>for (unsigned i = n; i --> 0 ;)
C>>    std::cout << i << std::endl;

BFE>Стандартная? А где массив?

Вот честное слово, не вижу разницы для иллюстративных целей — индексировать массив числами от 9 до 0 или выводить в стандартный вывод числа от 9 до 0.
Re[6]: Счетчик цикла, итераторы
От: Сыроежка  
Дата: 22.02.12 09:02
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Сыроежка, Вы писали:


С>>Все подготовлено для for. Поэтому пишем



С>>
С>>for ( size_t n = N; n--; ) a[n] = n;
С>>


E>Это неправильный for! Правильный должен иметь такую сруктуру
for( инициализация; проверка условия; сдвиг итератора )



Это "неправильный for" только в вашей голове. Любой компилятор на это for не жалуется, так как конструкция написана в соответствии со стандартом, в котором предложение for определяется следующим образом

for ( for-init-statement conditionopt; expressionopt) statement

Обратите внимание, что у элемента expression справа приписано opt, что означает optional, то есть необязательный.
Можно вообще писать предложение for в виде

for ( ;; ) statement;

E>Но, на самом деле, гемор начинается чуть позже, когда тебе надо поитерировать массив с конца и с шагом step.


E>Все проблемы лечатся, конечно, кодом вроде такого:
for( unsigned int i = N - 1; i < N; i -= STEP )
но я бы не назвал его интуитивно понятным...

E>Второй минус такого подхода -- он на итераторы не обобщается, но в итераторах и не надо ходить вниз, с другой стороны.

Кто вам сказал, что в итераторах не надо "ходить вниз"?! А как быть с алогритмом copy_backward, reverse и со всеми реверсивными итераторами?!


E>Но я вообще противник использования беззнаковых целых, без крайней на то нужды. Слишком легко допустить переполнение...


Без крайней нужды не следует использовать те типы, область значений которых не соответствует области используемых значений. То есть в циклах с индексом как раз без крайней нужды не слледует использовать знаковые типы, так как предполагается, что индекс не может иметь отрицательное значение.
Меня можно встретить на www.cpp.forum24.ru
Re[7]: Счетчик цикла, итераторы
От: Erop Россия  
Дата: 22.02.12 09:22
Оценка:
Здравствуйте, Сыроежка, Вы писали:


С>Это "неправильный for" только в вашей голове. Любой компилятор на это for не жалуется, так как конструкция написана в соответствии со стандартом, в котором предложение for определяется следующим образом


"Неправильный", в данном случае, обозначает "нечитабельный"...

С>Кто вам сказал, что в итераторах не надо "ходить вниз"?! А как быть с алогритмом copy_backward, reverse и со всеми реверсивными итераторами?!


Тот, кто рассказал об обратных иетраторах...


С>Без крайней нужды не следует использовать те типы, область значений которых не соответствует области используемых значений. То есть в циклах с индексом как раз без крайней нужды не слледует использовать знаковые типы, так как предполагается, что индекс не может иметь отрицательное значение.


Ну вот я считаю такой подход ошибочным. Аргументация -- слишком велик шанс допустить переполнение и не заметить этого. А какой смысл в твоём подходе? Что он даёт? ограничения же не проверяются?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Счетчик цикла, итераторы
От: MasterZiv СССР  
Дата: 22.02.12 09:49
Оценка: :)))
On 02/22/2012 01:22 PM, Erop wrote:

>

> "Неправильный", в данном случае, обозначает "нечитабельный"...
>
> С>Кто вам сказал, что в итераторах не надо "ходить вниз"?! А как быть с

Они нашли наконец друг друга !
Posted via RSDN NNTP Server 2.1 beta
Re[5]: Счетчик цикла, итераторы
От: B0FEE664  
Дата: 22.02.12 10:04
Оценка:
Здравствуйте, Centaur, Вы писали:

BFE>>>>Попробуйте написать цикл с использованием unsigned int, который перебирает элементы массива в обратном порядке — от хвоста к голове.

C>>>Стандартная идиома:
C>
C>>>for (unsigned i = n; i --> 0 ;)
C>>>    std::cout << i << std::endl;
C>

BFE>>Стандартная? А где массив?
C>Вот честное слово, не вижу разницы для иллюстративных целей — индексировать массив числами от 9 до 0 или выводить в стандартный вывод числа от 9 до 0.

Я спрсоня не смог правильно прочитать это цикл. Извините.
Спасибо за конструкцию. Столько лет программирую, а не знал
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.