Программирование >>  Немодифицирующие последовательные алгоритмы 

1 ... 29 30 31 [ 32 ] 33 34 35 ... 78


Initial sequence L2: 15 35

After Ll.merge(L2): 10 15 20 30 35

Последняя строчка вывода показывает новый список II, в то время как 11 становится пустым. Хотя имя функции merge совпадает с именем алгоритма merge, последний работает по-другому (см. раздел 1.7).

3.6. Векторы векторов

До сих пор в наших примерах излюбленным типом был vector<int>. Вполне очевидно, что мы можем заменить int на другой тип и использовать vector<double>, vector<char> и т. п. А вправе ли мы использовать более сложный тип, чем int, double и char, между двумя угловыми скобками? Например, можно ли написать

vector<vector<int> > А;

Да, возможно, как в следующей программе:

vecvec.cpp: Вектор векторов.

iinclude <iostream> iinclude <vector>

using namespace std;

int mainO

{ vector <int>v;

V.push back(8); v.push back(9);

vector<vector<int> > A;

A.push back(v);

A.push back(v);

A.push back(v);

for (int i=0; i<3; i++)

{ for (int j=0; j<2; j++)

cout A[i][j] ; cout endl;

return 0;

Программа использует вектор A, состоящий из трех элементов, каждый из которых является вектором, содержащим два целых числа 8 и 9. Мы можем считать вектор А двумерным массивом, или матрицей, как показывает вывод этой программы:



Следует иметь в виду, что предложенный автором второй вариант реализации двумерного массива с помощью вектора указателей не только менее эффективен по времени выполнения и менее защищен от случайного неправильного выделения/освобождения памяти (см. раздел 3.7), но в случае плотно заполненной матрицы может фактически использовать больше памяти, чем первый вариант, использующий вектор из векторов! В реальных программах на С++ подобных приемов следует избегать. - Прим. переводчика.

8 9 8 9 8 9

Однако такой подход может привести к тому, что нам потребуется больше памяти, чем действительно необходимо. Довольно часто программисты на С и С++ используют вместо двумерных массивов массивы указателей. Точно так же можно использовать вектор указателей, реализованный в следующей программе, вывод которой совпадает с предыдущей:

pointers.срр: Вектор указателей, iinclude <iostream> iinclude <vector> using namespace std;

typedef vector<int> vecint;

int main()

{ vector<vecint*> A; int a[2] = {8, 9}; A.push back(new vecint(a, a+2)) A.push back(new vecint(a, a+2)) A.push back(new vecint(a, a+2)) for (int i=0; i<3; i++) { for (int j=0; j<2; j++)

cout (*A[i])[j] ; cout endl;

delete A[0]; delete A[l]; delete A[2]; return 0;

Каждый элемент вектора A, A[i] является указателем на вектор из двух элементов целого типа, так что является этим вектором, содержа-

щим целые значения, доступ к которым осуществляется с помощью выражения *(/![?])[/].



3.7. Как избавиться от явного выделения памяти

Как было отмечено в разделе 1.14, в сложных программах к частым ошибкам приводит освобождение памяти с помощью/гее или delete. В данных ниже определениях функций нельзя обойтись без использования упомянутых выражений. Если же мы забудем сделать это, возникнет так называемая утечка памяти, то есть динамически вьщеленная память не будет освобождена:

void f(int n) { double *a;

a = (double*)malloc(n * sizeof(double));

... Используем a[0], a[n-l].

free(a); Bo избежание утечки памяти

либо

void f(int n) { double *a;

a = new double[n];

Используем a[0], a[n-l].

delete[] a; Bo избежание утечки памяти

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

Используя STL, мы можем избежать использования malloc и new, применяя контейнер vector. Преимущество этого подхода заключается в снижении риска неправильного использования/гее или delete. Например, вместо рассмотренной выше функции мы можем написать

♦include <vector> void f(int n)

{ vector<double> a(n); См. раздел 3.3.

Используем a[0], а[п-1].

Освобождение памяти теперь осуществляется деструктором контейнера. Векторы как члены классов

Векторы также можно использовать вместо определенных внутри классов массивов, которые размещаются и освобождаются явным образом. Рассмотрим для примера следующий код, использующий явное выделение и освобождение памяти:



1 ... 29 30 31 [ 32 ] 33 34 35 ... 78

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика