Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL5 / lab1-vector / lab1-vector.doc
Скачиваний:
12
Добавлен:
10.04.2015
Размер:
183.3 Кб
Скачать

Интеграция со старым с-кодом

Как уже упоминалось ранее, практически в любой ситуации вместо встроенного массива может (и должен) использоваться класс vector. Однако существует большое количество старого кода на С, использующего встроенные массивы, с которым должен корректно взаимодействовать новый код на С++ использующий классvector(Ни в коем случае не следует отказываться от использованияvectorтолько для обеспечения совместимости со старымC-кодом).

Предположим существует старый С интерфейс содержащий следующую функцию (важно отметить, что данная функция не модифицированные переданные ей данные):

void DoSomething(const int* array, int size);

Для того чтобы передать в данную функцию данные, содержащие в объекте класса vectorможно использовать следующий код:

vector<int> VectorOfInt;

DoSomething(&VectorOfInt[0], VectorOfInt.size());

Этот код будет работать корректно, так как стандарт гарантирует, что данные хранящиеся в векторе расположены в непрерывном фрагменте памяти, а код &VectorOfInt[0] позволяет получить указатель на первый элемент. Также важно отметить, что данные код будет работать во всех случаях кроме того, когда вектор не содержит элементов. В этом случае приведенный код может привести к неопределенному поведению, так как &VectorOfInt[0] будет указывать на неинициализированную область памяти. Код можно модифицировать следующим образом:

vector<int> VectorOfInt;

if ( ! VectorOfInt.empty() )

DoSomething(&VectorOfInt[0], VectorOfInt.size());

В случае если функция С интерфейса изменяет переданный ей массив

void ModifyArray(int* array, int size);

vector<int> VectorOfInt;

if ( ! VectorOfInt.empty() )

ModifyArray(&VectorOfInt[0], VectorOfInt.size());

то приведенный код будет работать, в случае если функция не изменяет количество элементов, не пытается создавать элементы в неинициализированной памяти зарезервированной реализацией вектора и не пытается вставлять новые элементы.

Возможна также ситуация, в которой функция С интерфейса должна заполнять массив, в этом случае необходимо создать вектор заданного размера, содержащий значения по умолчанию (например для целых чисел это нули), далее функция заполнит массив, изменяя значения по умолчанию:

// Функция fillArray получает указатель на массив,

// содержащий не более arraySize чисел типа double

// и записывает в него данные. Возвращаемое количество записанных

// чисел заведомо не превышает numMaxDouble

int fillArray(double* array, int size);

// Создать vector емкость которого равна numMaxDouble

vector<double> VectorOfDouble(numMaxDouble);

// Заполнить вектор вызовом функции fillArray, после чего изменить размер

// По количеству реально записанных элементов

VectorOfDouble.resize(fillArray(&VectorOfDouble[0], numMaxDouble));

Функции сравнения

Для вектора также определены операторы сравнения == и <:

template <class T, class A>

bool std :: operator == (const vector<T, A>&x, const vector<T, A>&y);

template <class T, class A>

bool std :: operator < (const vector<T, A>&x, const vector<T, A>&y);

Два вектора v1 иv2 считаются равными, еслиv1.size() ==v2.size() иv1[n] ==v2[n] для любого допустимого индексаn.

Сравнение < - лексикографическое сравнение (аналогичное сравнению строк с помощью функции strcmp). Векторv1 меньшеv2, если первыйv1[i] не равный соответствующемуv2[i], меньше, чемv2[i] или еслиv1.size() меньшеv2.size(), при равенстве всехv1[i] соответствующимv2[i]. Стандартная библиотека также предоставляет операторы !=, <=, >= с определениями соответствующими == и <.

vector<bool>

Частным случаем вектора является вектор, состоящий из элементов типа bool. Размер переменной типаboolне может быть меньше байта, а в некоторых реализациях С++ он равен 4 байтам, однако реально для хранения значения типаboolдостаточно 1 бита. Таким образом перерасход памяти равен 8 раз (32 раза в случае если размерboolравен 4 байта).vector<bool> реализованной в стандартной библиотеке осуществляет упаковку значение булевского типа, при этом сохраняя операции присутствующие в классеvector(например обращение по индексу или с помощью итераторов):

void f(vector<bool>&v)

{

//итерация через индексы

for (int i= 0; i < v.size(); i++)

cin >> v[i];

typedef vector<bool> :: const_iterator VI;

//итерация при помощи итераторов

for (VI p = v.begin(); p != v.end(); ++p)

cout << *p;

}

Чтобы добиться этого в случае упаковки значений boolв бит реализацияvector<bool> должна имитировать подобное поведение. Поскольку указатель не может адресовать единицу памяти, меньшую, чем байт, ссылка на элементvector<bool> не может быть обычной ссылкой, Ссылка на элемент вектора логических значений реализована в виде классаreference, моделирующего обычную ссылку на элемент:

class reference{

friend class vector;

reference();

public:

~reference();

operator bool() const;

reference& operator=(const bool x);

reference& operator=(const reference& x);

void flip();

};

Соответственно не имеет смысл получения адреса элемента vector<bool>, так как операция индексирования возвращает неbool*, аreference*. В силу этих и некоторых других особенностейvector<bool> не удовлетворяет требованиям стандарта к контейнерам и соответственно не является стандартным контейнером, следует избегать его использования

Более подробное описание vector<bool> можно найти в литературе по С++, здесь он приведен в качестве краткого описания и как пример реализации контейнера в которым операция индексирования вместо ссылки возвращаетproxy-объект (объект посредник), через который осуществляется доступ к реальному значению.

1Имеется в виде случай, когда массив имеет определенный размер, но содержит переменное количество элементов (используется не вся память, выделенная под массив)

2Контейнеры - объекты, содержащие внутри себя другие объекты. Контейнеры управляют размещением в памяти и освобождением этих объектов через конструкторы, деструкторы, операции вставки и удаления.

3Более подробно итераторы будут рассмотрены позднее. Пока можно представлять себе итераторы как указатели на элементы контейнера.

4Описание итераторов и функцийbegin(),end(),rbegin(),rend() приведено ниже.

5Подробно итераторы рассмотрены в одной из следующих работ. Здесь кратко приводятся основные сведения.

6Итераторы произвольного доступа и другие типы итераторов более детально рассмотрены в работе посвященной итераторам.

7Особенности работы класса вектор связанные с изменением размера более детально рассмотрены далее

8Стек – это частный случай однонаправленного списка, добавление элементов в который и выборка из которого выполняется с одного конца, называемого вершиной стека. Другие операции со стеком не определены. При выборке элемент исключается из стека. Стек реализует принцип обслуживанияLIFO(lastin–firstout, последним пришел, последним ушел).

9Более подробно функцияsize() рассмотрена ниже

10Более подробно вопрос рассматривается ниже

Соседние файлы в папке lab1-vector