首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >提取原始数据,然后将其传递到另一个类中-如何避免在保持封装的同时复制两次?

提取原始数据,然后将其传递到另一个类中-如何避免在保持封装的同时复制两次?
EN

Stack Overflow用户
提问于 2010-03-25 08:18:32
回答 5查看 836关注 0票数 5

考虑一个包含class Page的stl容器的class Book。每个Page包含一个屏幕截图,就像原始vector<char>表单中的page10.jpg一样。

打开一个Book,其中包含一个zip、rar或包含这些屏幕截图的目录的路径,并使用各自的方法来提取原始数据,如ifstream inFile.read(buffer, size);unzReadCurrentFile(zipFile, buffer, size)。然后,它调用Page(const char* stream, int filesize)构造函数。

现在,很明显原始数据被复制了两次。一次提取到图书的本地buffer,第二次在Page ctor中提取到Page::vector<char>。有没有一种方法可以在消除中间人缓冲区的同时保持封装?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-03-25 09:23:54

根据已有的代码更改,最简单的方法可能是为Page提供一个setter方法,该方法采用非常量向量引用或指针,并使用Page中包含的向量对其进行swap。调用者将保留一个空向量,但由于问题是过度复制,因此调用者可能不想保留数据:

代码语言:javascript
复制
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);
    }
};

有些人(例如谷歌C++风格指南)希望引用参数为常量,并希望您将newcontent参数作为指针传递,以强调它是非常量:

代码语言:javascript
复制
void setContent(std::vector<char> *newcontent) {
    content.swap(*newcontent);
}

swap速度很快--你会期望它只交换两个矢量对象的缓冲区指针和大小。

或者,为Page提供两个不同的构造函数:一个用于zip文件,另一个用于常规文件,并让它负责读取自己的数据。这可能是最干净的,而且它允许Page是不可变的,而不是在构造之后被修改。但实际上您可能不希望这样,因为正如您在注释中注意到的那样,将Page添加到容器中会复制Page。因此,在容器中以较低的成本构造数据之后,能够修改页面以添加数据有一些好处:它避免了额外的复制,而不需要处理指针容器。尽管如此,setContent函数可以像获取向量一样轻松地获取文件流/压缩文件信息。

您可以找到或编写一个从zipfile读取数据的流类,这样Page就可以只使用一个获取流的构造函数来负责读取数据。或者可能不是整个流类,也许只是您设计的一个接口,它将数据从stream/zip/rar读取到指定的缓冲区中,Page可以将其内部向量指定为缓冲区。

最后,你可以“搞乱指针的容器”。将pages设置为std::vector<boost::shared_ptr<Page> >,然后执行以下操作:

代码语言:javascript
复制
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具有适度的开销(它为包含指针和引用计数的小节点分配了额外的内存),但复制成本要低得多。它也是用TR1编写的,如果你有Boost之外的其他实现。

票数 3
EN

Stack Overflow用户

发布于 2010-03-25 08:23:23

最初使用std::vector resize成员设置缓冲区大小,然后通过front()的地址直接使用其缓冲区。

代码语言:javascript
复制
std::vector<char> v;
v.resize(size);
strcpy(&v.front(), "testing");

&v.front()提供了对std::vector的直接缓冲区访问

票数 2
EN

Stack Overflow用户

发布于 2010-03-25 09:07:48

使用std::vector保存图像数据不是一个好主意。为此,我将使用原始指针或shared_ptr。这可以防止缓冲区被复制两次。

因为你关心内存,所以在内存中保存所有的图像数据对我来说也不是一个好主意。一种更好的方法是将其封装到单独的类中。例如,ImageData。该类包含图像数据的行指针。首先可以使用文件路径初始化该类,然后在需要时从磁盘加载图像数据。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2512371

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档