Первый, рассмотренный в этой теме пример был бы не полным без одного уточнения. В этом примере значения массива задавались при его инициализации в списке инициализации:
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Это упрощение не ограничивает общности подхода к сравнению вида кода в С++ 2003 и в С++ 2011. Но тем не менее и здесь, то есть по отношению к этой строке инициализации массива можно продемонстрировать различия С++ 2003 и С++ 2011.
Это различие проявит себя, если задаться вопросом, а как можно задать последовательные значения массива равными 1, 2,..., n не в списке инициализации, а алгоритмическим способои? Ведь не всегда массивы имеют столь мало элементов, что можно их инициализировать "вручную".
Опять-таки для простоты примем размер массива таким же, как и в исходном примере.
const int SIZE = 9;
Но теперь поставим задачу инициализировать массив алгоритмически. Самый простой путь в С++ 2003 - это по-прежнему использовать цикл.
for ( int i = 1; i < SIZE; i++ ) a[ i ] = i + 1;
А как это сделать с помощью стандартных аллгоритмов в С++ 2003? Увы, простого пути нет. Возможное решение задачи следующее:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <numeric>
int main()
{
const int SIZE = 9;
int a[SIZE];
std::fill( a, a + SIZE, 1 );
std::partial_sum( a, a + SIZE, a );
std::copy( a, a + SIZE,
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << sttd::endl;
}
В этом примере сначала с помощью стандартного алгоритма
std::fill, объявленного в
<algorithm>, всем элементам массива присваивается одно и то же значений, равное 1. А затем используется стандартный алгоритм
std::partial_sum, объявленный в заголовочном файле
<numeric>, который подсчитывает частичные суммы исходного массива и присваивает их элементам этого же массива. То есть a[0] так и останется равным 1. a[1] будет равно 1 + a[1], то есть 2. a[2] будет равно 2 + a[2], то есть 3 и т.д.
Конечно для контейнеров с прямым доступом к элементам, как, например, для массивов или векторов, проще использовать цикл. Для последовательных контейнеров типа
std::list этот цикл уже не будет таким простым, так как надо организовать еще перемещение по элементам коонтейнера. Поэтому для контейнеа
std::list лучше организовать цикл с помощью итераторов, например,
#include <iostream>
#include <iterator>
#include <algorithm>
#include <list>
int main()
{
const int SIZE = 9;
std::list<int> l( SIZE, 1 );
std::list<int>::iterator it = l.begin();
int sum = *it;
while ( ++it != l.end() )
{
sum += *it;
*it = sum;
}
std::copy( l.begin(), l.end(),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << sttd::endl;
}
Как видно из примера, это тоже не простой путь, а самое главное, требует от читающего код затратить определенное время и умственные усилия, чтобы разобраться, что этот код делает. Хуже еще то, что в одной и той же программе для разных типов контейнеров могут использоваться различные подходы для решения данной задачи, то есть для массивов будет использоваться цикл с прямым доступом к элементам, для списков - другой цикл с итераторами. а для векторов, допустим, - третий с использованием стандартных алгоритмов
std::fill и
std::partiall_sum, как было показано выше.
Что же предлагает новый стандарт С++ 2011 для решения подобной задачи?
В стандарте С++ 2011 в библиотеки
<numeric> появился новый алгоритм (если я не ошибаюсь, это единственное изменение библиотеки
<numeric> в станларте С++ 2011)
std::iota. Он как раз и предназначен для решения подобной задачии. Теперь с его появлением можно для всех ттипов контейнеров использовать один и тот же метод. Например,
#include <iostream>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <list>
int main()
{
const int SIZE = 9;
int a[SIZE];
std::iota( std::begin( a ), std::end( a ), 1 );
std::copy( std::begin( a ), std::end( a ),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
std::list<int> l( SIZE );
std::iota( l.begin(), l.end(), 1 );
std::copy( l.begin(), l.end(),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << sttd::endl;
}
Главное достоинство этого подхода состоит в том, что стандартные алгоритмы - это тот язык общения между программистами, который понятен любому квалифицированному программисту, в отличии от оригинальных конструкций, придумываемых каждым программистом самостоятельно в своем коде.