Однако сам вектор не может храниться непосредственно в объекте Blob. Члены объекта удаляются при удалении самого объекта. Предположим, например, что объекты b1 и b2 класса Blob совместно используют тот же вектор. Если бы вектор хранился в одном из этих объектов, скажем в b2, то, как только объект b2 выйдет из области видимости, элементы вектора перестанут существовать. Чтобы гарантировать продолжение существования элементов, будем хранить вектор в динамической памяти.

Для реализации совместного использования снабдим каждый объект класса StrBlob указателем shared_ptr на вектор в динамической памяти. Указатель-член shared_ptr будет следить за количеством объектов класса StrBlob, совместно использующих тот же самый вектор, и удалит его, когда будет удален последний объект класса StrBlob.

Осталось решить, какие функции будет предоставлять создаваемый класс. Реализуем пока небольшое подмножество функций вектора. Изменим также функции обращения к элементам (включая front() и back()): в данном классе при попытке доступа к не существующим элементам они будут передавать исключения.

У класса будет стандартный конструктор и конструктор с параметром типа initializer_list (см. раздел 6.2.6). Этот конструктор будет получать список инициализаторов в скобках.

class StrBlob {

public:

 typedef std::vector::size_type size_type;

 StrBlob();

 StrBlob(std::initializer_list il);

 size_type size() const { return data->size(); }

 bool empty() const { return data->empty(); }

 // добавление и удаление элементов

 void push_back(const std::string &t) {data->push_back(t);}

 void pop_back();

 // доступ к элементам

 std::string& front();

 std::string& back();

private:

 std::shared_ptr> data;

 // передать сообщение при недопустимости data[i]

 void check(size_type i, const std::string &msg) const;

};

В классе будут реализованы функции-члены size(), empty() и push_back(), которые передают свою работу через указатель data внутреннему вектору. Например, функция size() класса StrBlob вызывает функцию data->size() и т.д.

Конструкторы класса StrBlob

Для инициализации своей переменной-члена data указателем на динамически созданный вектор каждый конструктор использует собственный список инициализации (см. раздел 7.1.4). Стандартный конструктор резервирует пустой вектор:

StrBlob::StrBlob(): data(make_shared>()) { }

StrBlob::StrBlob(initializer_list il):

 data(make_shared>(il)) { }

Конструктор, получающий тип initializer_list, передает свой параметр для соответствующего конструктора класса vector (см. раздел 2.2.1). Этот конструктор инициализирует элементы вектора копиями значений из списка.

Функции-члены доступа к элементам

Функции pop_back(), front() и back() обращаются к соответствующим функциям-членам вектора. Эти функции должны проверять существование элементов прежде, чем попытаться получить доступ к ним. Поскольку несколько функций-членов должны осуществлять ту же проверку, снабдим класс закрытой вспомогательной функцией check(), проверяющей принадлежность заданного индекса диапазону. Кроме индекса, функция check() получает аргумент типа string, передаваемый обработчику исключений. Строка описывает то, что пошло не так, как надо:

void StrBlob::check(size_type i, const string &msg) const {

 if (i >= data->size())

  throw out_of_range(msg);

}

Функция pop_back() и функции-члены доступа к элементам сначала вызывают функцию check(). Если проверка успешна, эти функции-члены передают свою работу соответствующим функциям вектора:

strings StrBlob::front() {

 // если вектор пуст, функция check() передаст следующее

 check(0, "front on empty StrBlob");

 return data->front();

}

strings StrBlob::back() {

 check(0, "back on empty StrBlob");

 return data->back();

}

void StrBlob::pop_back() {

 check(0, "pop_back on empty StrBlob");

 data->pop_back();

}

Перейти на страницу:

Похожие книги