С точки зрения изменений кода, основанных на том, что у вас уже есть, простейшим, вероятно, является предоставление Page установщика, принимающего неконстантную векторную ссылку или указатель, и swap
его с вектором, содержащимся на странице. Вызывающая сторона останется с пустым вектором, но поскольку проблема заключается в избыточном копировании, предположительно вызывающая сторона не хочет сохранить данные:
void Book::addPage(ifstream file, streampos size) {
std::vector<char> vec(size);
file.read(&vec[0], size);
pages.push_back(Page()); // pages is a data member
pages.back().setContent(vec);
}
class Page {
std::vector<char> content;
public:
Page() : content(0) {} // create an empty page
void setContent(std::vector<char> &newcontent) {
content.swap(newcontent);
}
};
Некоторые люди (например, руководство по стилю Google C ++) хотят, чтобы ссылочные параметры были константными, и хотели бы, чтобы вы передавали параметр newcontent
в качестве указателя, чтобы подчеркнуть, что он не является константным:
void setContent(std::vector<char> *newcontent) {
content.swap(*newcontent);
}
swap
быстр - вы ожидаете, что он просто поменяет указатели буфера и размеры двух векторных объектов.
В качестве альтернативы, предоставьте Page два разных конструктора: один для zip-файла и один для обычного файла, и пусть он будет отвечать за чтение своих собственных данных. Это, вероятно, самый чистый вариант, и он позволяет Page быть неизменным, а не изменяться после создания. Но на самом деле вы можете этого не хотеть, поскольку, как вы заметили в комментарии, добавление страницы в контейнер копирует страницу. Таким образом, есть некоторая выгода от возможности модификации Страницы для добавления данных после того, как она была дешево сконструирована в контейнере: она позволяет избежать этой дополнительной копии без необходимости связываться с контейнерами указателей. Тем не менее, функция setContent
может так же легко получить информацию о потоке файла / файле zip, как и вектор.
Вы можете найти или написать потоковый класс, который читает из zip-файла, так что Page может быть ответственным за чтение данных, когда только один конструктор принимает поток. Или, может быть, не целый класс потока, возможно, просто разработанный вами интерфейс, который считывает данные из потока / zip / rar в указанный буфер, и Page может указать свой внутренний вектор в качестве буфера.
Наконец, вы можете "связываться с контейнерами указателей". Сделайте pages
a std::vector<boost::shared_ptr<Page> >
, затем сделайте:
void Book::addPage(ifstream file, streampos size) {
boost::shared_ptr<Page> page(new Page(file, size));
pages.push_back(page); // pages is a data member
}
A shared_ptr
имеет небольшие накладные расходы по сравнению только с страницей (он выделяет дополнительную память для небольшого узла, содержащего указатель и счетчик ссылок), но намного дешевле для копирования. Это тоже в TR1, если у вас есть какая-то реализация, отличная от Boost.