С точки зрения изменения кода, основанного на том, что у вас уже есть, самым простым, возможно, является предоставление Page set set, принимающего неконстантную векторную ссылку или указатель, и 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
быстро - вы бы ожидать, что это просто заменить буфер указатели и размеры двух векторных объектов.
В качестве альтернативы, дайте Странице два разных конструктора: один для zip-файла и один для обычного файла и нести ответственность за чтение своих собственных данных. Это, пожалуй, самое чистое, и это позволяет Page быть неизменным, а не изменяться после строительства. Но на самом деле вы можете этого не захотеть, поскольку, как вы заметили в комментарии, добавление страницы в контейнер копирует страницу. Таким образом, есть некоторая польза от возможности изменить страницу, чтобы добавить данные после, она была дешево построена в контейнере: она избегает этой дополнительной копии, не требуя прикосновения с контейнерами указателей. Тем не менее, функция setContent
может так же легко взять файл/файл zip-файла, как взять вектор.
Вы можете найти или написать класс потока, который читает из zip-файла, так что страница может отвечать за чтение данных только одним конструктором, принимающим поток. Или, возможно, не весь класс потока, возможно, только интерфейс, который вы создаете, который считывает данные из потока/zip/rar в указанный буфер, а страница может указывать свой внутренний вектор в качестве буфера.
И, наконец, вы можете «испортить контейнеры указателей». Сделать pages
в 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
}
shared_ptr
имеет скромные накладные относительно просто Page (это дополнительное выделение памяти для небольшого узла, содержащего указатель и RefCount), но много дешевле скопировать. Это также в TR1, если у вас есть реализация, отличная от Boost.
О, хорошо, я не думал об использовании swap. Я думал о том, что страница обрабатывает данные. Дело в том, что я буду постоянно открывать zipfile, прыгать и читать 1 изображение и закрывать его. Еще хуже то, что библиотека unrar не поддерживает переход к элементам. – Kache
«Я буду постоянно открывать zipfile, прыгать и читать 1 изображение и закрывать его» - не обязательно. Предположительно, ваш класс 'Book' в настоящее время продвигается через zip/rar, просматривая один файл за раз. Конструктор 'Page' может иметь такое же поведение, что он« потребляет »некоторые данные из переданного ему объекта. Просто будьте осторожны при обработке ошибок - потому что вы прочитали некоторые данные, и, вероятно, нет способа вернуть позицию потока туда, где она была запущена (если вы не можете перейти к файлу, вы не можете искать), вы можете только предложить слабая гарантия исключения. –