2013-10-21 101 views
1

下面是两段代码。一个人工作,一个人不工作,我想知道为什么。我事先对缺乏评论和糟糕的变数名称表示歉意,但现在这种语言真的磨砺我的齿轮。为什么这段代码不能用文件流切换cin和cout?

// File1.cpp (contains relevant includes) 
// Works! It writes to out.txt and appears to use in.txt correctly 
int main(int argc, char* argv[]) { 
    int num; 
    std::ifstream in("in.txt"); 
    std::streambuf* cinbuf = std::cin.rdbuf(); 
    std::cin.rdbuf(in.rdbuf()); 

    std::ofstream out("out.txt"); 
    std::streambuf* coutbuf = std::cout.rdbuf(); 
    std::cout.rdbuf(out.rdbuf()); 

    cout << "Give me a number: "; 
    cin >> num; 

    std::cin.rdbuf(cinbuf); 
    std::cout.rdbuf(coutbuf); 

    return 0; 
} 

// File2.cpp (contains relevant includes) 
// Does not work! Outputs nothing to out.txt. 
class TestWithStdIO { 
     std::streambuf* cinbuf; 
     std::streambuf* coutbuf; 
    public: 
     TestWithStdIO(const char* inFile, const char* outFile) { 
      std::ifstream in(inFile); 
      cinbuf = std::cin.rdbuf(); 
      std::cin.rdbuf(in.rdbuf()); 

      std::ofstream out(outFile); 
      coutbuf = std::cout.rdbuf(); 
      std::cout.rdbuf(out.rdbuf()); 
     } 
     ~TestWithStdIO() { 
      std::cin.rdbuf(cinbuf); 
      std::cout.rdbuf(coutbuf); 
     } 
}; 

int main(int argc, char* argv[]) { 
    int num; 
    TestWithStdIO* ioTest = new TestWithStdIO("in.txt", "out.txt"); 
    cout << "Give me a number: "; 
    cin >> num; 
    delete ioTest; 

    return 0; 
} 
+3

'in'和'out'只存在于构造函数调用的堆栈中。只要构造函数完成,它们就会“死亡”。也许使它们成为成员变量(并将文件名传递给[初始化程序列表](http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/)以打开它们)。 – BoBTFish

+0

@BoBTFish你应该做出答案,因为它是什么错。 (嗯,他动态地分配'TestWithStdIO'的事实也是错误的。'TestWithStdIO'基本上是RAII,RAII和动态分配对我来说似乎是一成不变的。) –

+0

@JamesKanze更不用说这样的原始指针不是例外安全。 – syam

回答

1

std::[io]fstreamsinout具有TestWithStdIO构造内部本地范围(或自动存储持续时间)。在函数结束时,它们被销毁(和文件关闭)以及它们所包含的缓冲区,留在cincout内部的悬挂指针。

考虑,而不是使得TestWithStdIOinout成员,是这样的:

class TestWithStdIO { 
     std::streambuf* cinbuf; 
     std::streambuf* coutbuf; 

     std::ifstream in_; // <-- member 
     std::ofstream out_; // <-- member 
    public: 
     TestWithStdIO(const std::string& inFile, const std::string& outFile) : 
      in_(inFile), out_(outFile) // <-- initializer list 
     { 
      cinbuf = std::cin.rdbuf(); 
      std::cin.rdbuf(in_.rdbuf()); 

      coutbuf = std::cout.rdbuf(); 
      std::cout.rdbuf(out_.rdbuf()); 
     } 
     ~TestWithStdIO() { 
      std::cin.rdbuf(cinbuf); 
      std::cout.rdbuf(coutbuf); 
     } 
}; 

您可能需要in(inFile.c_str()),等效为out如果你只有C++03支持。

另外,正如评论中指出的那样,不需要动态分配实例,实际上它可能是错误的来源。只是做

TestWithStdIO ioTest ("in.txt", "out.txt"); 
+0

很好的答案,非常感谢你:) –

1

TestWithStdIO::TestWithStdIO(),位流缓存器指向in.rdbuf()是(在构造的端部即)与in一起破坏。