如何返回一个fstream(C++0x)

7

我想直接开始编码:

#include <iostream>
#include <fstream>
#include <string>

class test : public std::ofstream
{
    public:
        test(const std::string& filename) { this->open(gen_filename(filename)); };
        test(const test&) = delete;
        //test(test&& old) = default; // Didn't compile
        test(test&& old) {};
    private:
        std::string gen_filename(const std::string& filename) 
        { return filename + ".tmp"; }
};

int main()
{
    auto os = test("testfile");
    os << "Test1\n";
    os << "Test2\n";
}

基本上,我需要返回一个ofstream。当然,你不能复制一个ofstream,因此在类测试中,我围绕着代码进行了一些调整,并且我让以上的代码进行编译和工作,就像你期望的那样(在gcc 4.5上)。

但是我有一种不好的感觉,这只是因为我的编译器对“auto os = test()”执行了“返回值优化”(RTO)。实际上,如果修改为以下内容:

int main()
{
    auto os = test("testfile");
    os << "Test1\n";
    auto os2 = std::move(os);
    os2 << "Test2\n";
}

我在输出中不再同时获得Test1和Test2。
问题是,类“test”不可复制,因此没有复制ofstream的机会。我只想能够从函数中返回它。而且我似乎可以使用GCC做到这一点。
我不想使用智能指针解引用堆分配的ofstream或重新打开文件,因为目前在不进行这些操作的情况下就可以正常工作。我只是有点“非标准”地处理,所以能有一种标准方法来完成我所描述的内容就好了。
3个回答

16

我将在这里回答自己的问题:

GCC C++0x库特性页面中,看一下第27.9项,它写道:

27.9 - 基于文件的流 - 部分 - 缺少移动和交换操作

我想这可能是我在使用gcc时遇到的问题。


是的,那就可以了。不过很好找到了。 - GManNickG
现在仍然正确吗? - Prof. Falken
好像不是这样的。如果可以的话,请随意编辑问题和答案。 - Clinton

2
问题出在这里:
test(test&& old) {};

这让你能够从一个右值 test 构造出一个新的 test,但它并未涉及到你的基类,基类只会被默认构造(没有打开文件)。你需要的是这个:
test(test&& old) : std::ofstream(std::move(old)) {};

这将把来自old的数据流移动到基础流中。


1
你的答案在gcc 4.5上出现了以下编译错误:"'std :: ios_base :: ios_base(const std :: ios_base&)'是私有的"。你确定你已经编译成功了吗?如果是这样,你用的是什么编译器? - Clinton
@Clinton:虽然我以前做过很多次,但我还没有尝试编译你的代码。(注意,“它可以编译”并不一定是测试它是否正确的C++代码)。你应该编辑你的问题,包括你正在尝试的新代码和所有的错误信息。 - GManNickG
你确定 ofstream 有一个右值构造函数吗? - Clinton
@Clinton:是的,在C++0x中。确保你启用了它进行编译。 - GManNickG
在C++0x中,您应该能够直接返回或移动ofstream,而无需将其包装在测试中。虽然通过已修正的测试移动构造函数,包装也是正确的。 - Howard Hinnant

0

调用方是否需要知道你返回了一个 ofstream,或者返回一个streambuf并让调用方在流中包装它更有意义?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接