En términos de cambios de código basados en lo que ya ha hecho, lo más simple es dar a la Página un setter tomando una referencia de vector no const o puntero, y swap
con el vector contenido en la Página. La persona que llama se queda con un vector vacío, pero ya que el problema es la copia excesiva, presumiblemente la persona que llama no quiere para mantener los datos:
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);
}
};
Algunas personas (por ejemplo, el Google C++ guía de estilo) quieren parámetros de referencia para ser const, y querría que pasa el parámetro newcontent
como un puntero, al destacar que es no constante:
void setContent(std::vector<char> *newcontent) {
content.swap(*newcontent);
}
swap
es rápido - se espera también sólo para intercambiar el tampón punteros y tamaños de los dos objetos vectoriales.
O bien, proporcione a Page dos constructores diferentes: uno para el archivo zip y otro para el archivo normal, y hágalo responsable de leer sus propios datos. Este es probablemente el más limpio, y permite que Page sea inmutable, en lugar de modificarse después de la construcción. Pero, en realidad, es posible que no lo desee, ya que como ha notado en un comentario, al agregar la Página a un contenedor, se copia la Página. Por lo tanto, hay algunos beneficios de poder modificar la página para agregar los datos después de que se ha fabricado de forma económica en el contenedor: evita esa copia adicional sin necesidad de meterse con los contenedores de punteros. Aún así, la función setContent
podría tomar fácilmente la información del archivo/archivo zip como tomar un vector.
Puede buscar o escribir una clase de flujo que lea desde un archivo zip, de modo que Page puede ser responsable de leer los datos con solo un constructor tomando una secuencia. O tal vez no una clase de flujo completo, tal vez solo una interfaz que diseñe, que lea datos de un flujo/zip/rar en un búfer especificado, y Page pueda especificar su vector interno como el búfer.
Finalmente, podría "meterse con contenedores de punteros". Hacer pages
un std::vector<boost::shared_ptr<Page> >
, a continuación, hacer:
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
}
Un shared_ptr
tiene un pariente sobrecarga modesta de sólo una página (que tiene una asignación de memoria adicional para un pequeño nodo que contiene un puntero y una refcount), pero es mucho más barato de copiar. También está en TR1, si tiene alguna implementación de eso aparte de Boost.
Oh, bueno, no pensé en usar swap. Pensé en tener a Page manejar la lectura de datos. La cosa con eso estaría constantemente abriendo un archivo zip, saltando y leyendo una imagen, y cerrándola. Peor aún, la biblioteca unrar no admite saltar a los artículos. – Kache
"Abría constantemente un archivo zip, saltaba y leía 1 imagen y la cerraba", no necesariamente. Presumiblemente, su clase 'Book' actualmente avanza por el zip/rar leyendo un archivo a la vez. El constructor 'Page' podría tener el mismo comportamiento, que" consume "algunos datos del objeto que se le pasa. Solo tenga cuidado al manejar los errores, porque ha leído algunos datos y probablemente no haya forma de volver a poner la posición del flujo en el punto inicial (si no puede saltar a un archivo, no puede buscar), solo puede ofrecer la débil garantía de excepción. –