Литмир - Электронная Библиотека
A
A

array<int,256> gb; // 256 целых чисел

array<double,6> ad = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 }; // инициализатор!

const int max = 1024;

void some_fct(int n)

{

  array<char,max> loc;

  array<char,n> oops;         // ошибка: значение n компилятору

                              // неизвестно

  // ...

  array<char,max> loc2 = loc; // создаем резервную копию

  // ...

  loc = loc2;                 // восстанавливаем

  // ...

}

Ясно, что класс array очень простой — более простой и менее мощный, чем класс

vector
, — так почему иногда следует использовать его, а не класс
vector
? Один из ответов: “эффективность”. Размер объекта класса array известен на этапе компиляции, поэтому компилятор может выделить статическую память (для глобальных объектов, таких как
gb
) или память в стеке (для локальных объектов, таких как
loc
), а не свободную память. Проверяя выход за пределы диапазона, мы сравниваем константы (например, размер N). Для большинства программ это повышение эффективности незначительно, но если мы создаем важный компонент системы, например драйвер сети, то даже небольшая разница оказывается существенной. Что еще более важно, некоторые программы просто не могут использовать свободную память. Такие программы обычно работают во встроенных системах и/или в программах, для которых основным критерием является безопасность (подробно об этом речь пойдет в главе 25). В таких программах массив
array
имеет много преимуществ над классом vector без нарушения основного ограничения (запрета на использование свободной памяти).

Поставим противоположный вопрос: “Почему бы просто не использовать класс

vector
?”, а не “Почему бы просто не использовать встроенные массивы?” Как было показано в разделе 18.5, массивы могут порождать ошибки: они не знают своего размера, они конвертируют указатели при малейшей возможности и неправильно копируются; в классе
array
, как и в классе
vector
, таких проблем нет. Рассмотрим пример.

double* p = ad;        // ошибка: нет неявного преобразования

                       // в указатель

double* q = ad.data(); // OK: явное преобразование

template<class C> void printout(const C& c) // шаблонная функция

{

  for (int i = 0; i<c.size(); ++i) cout << c[i] <<'\n';

Эту функцию

printout()
можно вызвать как в классе
array
, так и в классе
vector
.

printout(ad); // вызов из класса array

vector<int> vi;

// ...

printout(vi); // вызов из класса vector

Это простой пример обобщенного программирования, демонстрирующий доступ к данным. Он работает благодаря тому, что как для класса

array
, так и для класса
vector
используется один и тот же интерфейс (функции
size()
и операция индексирования). Более подробно этот стиль будет рассмотрен в главах 20 и 21. 

19.3.5. Вывод шаблонных аргументов

 Создавая объект конкретного класса на основе шаблонного класса, мы указываем шаблонные аргументы. Рассмотрим пример.

array<char,1024> buf; // для массива buf параметр T — char, а N == 1024

array<double,10> b2;  // для массива b2 параметр T — double, а N == 10

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Для шаблонной функции компилятор обычно выводит шаблонные аргументы из аргументов функций. Рассмотрим пример.

template<class T, int N> void fill(array<T,N>& b, const T& val)

{

  for (int i = 0; i<N; ++i) b[i] = val;

}

void f()

{

  fill(buf, 'x'); // для функции fill() параметр T — char,

                  // а N == 1024,

                  // потому что аргументом является объект buf

  fill(b2,0.0);   // для функции fill() параметр T — double,

                  // а N == 10,

                  // потому что аргументом является объект b2

}

С формальной точки зрения вызов

fill(buf,'x')
является сокращенной формой записи
fill<char,1024>(buf,'x')
, а
fill(b2,0)
— сокращение вызова
fill<double,10>(b2,0)
, но, к счастью, мы не всегда обязаны быть такими конкретными. Компилятор сам извлекает эту информацию за нас. 

19.3.6. Обобщение класса vector

Когда мы создавали обобщенный класс

vector
на основе класса “
vector
элементов типа
double
” и вывели шаблон “
vector
элементов типа
T
”, мы не проверяли определения функций
push_back()
,
resize()
и
reserve()
. Теперь мы обязаны это сделать, поскольку в разделах 19.2.2 и 19.2.3 эти функции были определены на основе предположений, которые были справедливы для типа
double
, но не выполняются для всех типов, которые мы хотели бы использовать как тип элементов вектора.

260
{"b":"847443","o":1}