将std :: stream对象从一个管理器传递到另一个管理器

时间:2014-01-06 16:06:01

标签: c++ c++11 stream

我正在为我的游戏实现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

的包装器

3 个答案:

答案 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)

有三种传递流的方式(我认为):

  • 作为参数(对函数的非常量引用)
  • 作为封装在智能指针中的返回值 (std / boost :: shared_ptr或unique_ptr)
  • 移动语义(编译器可能不支持)