我正在为我的游戏实现ResourceManager,我遇到了一些关于Streams的问题。
在我的资源管理器中,有一个Locator对象可以搜索文件。当定位器找到文件时,它返回一个ResourceStream对象(virtual ResourceStream * FileLocator::locateFile(const String &name);
)。然后,Loader对象解析该文件并创建一个Resource对象(例如virtual Resource * ResourceLoader::parseStream(ResourceStream * stream);
)。
问题是,我不知道如何实现ResourceStream,因为我真的不知道如何使用std :: streams。作为一种好的做法,流如何在对象之间传递?它是应该通过指针传递还是移动语义,考虑到它,在范围的末尾将删除流?在上面的问题中,我应该如何移动流?我应该使ResourceStream继承自std::fstream
并通过std::move
传递吗?或者我应该使用ResourceStream围绕std::streambuf
?
答案 0 :(得分:1)
通常的解决方案是通过引用传递,但是根据您的描述,流将在单独的函数中创建并从其返回,并且应该超出创建函数的生命周期。传统上,您将返回指向动态分配的流的指针,被调用者必须删除该流。 (这是std::auto_ptr
的设计目标。)在C ++ 11中,此解决方案仍然有效(但您可能希望使用std::unique_ptr
)。或者,您可以使用移动语义进行返回,尽管它们不会尊重多态类型。换句话说:如果locateFile
创建std::ifstream
,则使用其返回值初始化的局部变量必须是std::ifstream
,而不仅仅是std::istream
。这可能会暴露locateFile
的内部过多,并使std::auto_ptr
/ std::unique_ptr
解决方案更受欢迎。
答案 1 :(得分:1)
考虑实现stream buffer(可以作为参数传递)。当你需要缓冲区上的I / O时,在它上面创建一个std :: istream或std :: ostream。
这种方法允许您使用std::[i/o]stream
访问格式正确的I / O,而不需要您付出任何努力(即您只需要定义从流中添加或获取字节的含义,而不是格式化。< / p>
代码应如下所示:
class ResourceStream: public std::streambuf {
... // you implement this
};
virtual Resource parseStream(std::streambuf * streambuf)
{
std::istream in(streambuf);
Resource r;
in >> r; // assumes an std::istream& operator>>(std::istream&in, Resource& r)
// is defined
if(in >> r)
return r;
else
throw std::runtime_error{"bad stream for parsing resource"};
}
编辑:
再看看,这似乎是x-y问题。正确的解决方案是为您的Resource类定义i / o运算符:
你需要写什么:
class Resource {
// ...
};
std::istream& operator >> (std::istream& in, Resource& r) {
return in after reading from it
}
std::ostream& operator << (std::ostream& out, const Resource& r) {
return in after writing into it
}
在您的模型中,ResourceStream对象将是在找到的文件上打开的std :: ifstream,您的ResourceManager将如下所示:
// boost::path can be replaced by std::string containing the file path
virtual boost::path FileLocator::locateFile(const String &name);
// locate file and get resource:
auto path = locator.locateFile("serializedresource.data");
std::ifstream input(path);
Resource r;
if(input >> r)
// r was read correctly
else
// stream does not contain a serialized r / throw an exception
答案 2 :(得分:1)
有三种传递流的方式(我认为):