【问题标题】:close an unopened stream关闭未打开的流
【发布时间】:2010-09-16 17:39:26
【问题描述】:

我有 ifstream 和一个在运行时可能打开或不打开的 ofstream(取决于用户在命令行中输入的内容。无论如何我都声明了变量,并且我有一个方法可以在需要时打开流。 我的问题是在程序结束时我不知道是否需要关闭它们。

C++ 中是否有任何方法可以知道是否打开了流?就像在 Java 中一样,您可以给流一个 null 值,然后询问它是否为 null(这意味着它从未打开过)..

是否可以关闭从未打开的流?

这是代码:

int main(int argc, char* argv[]) {

    static std::ifstream ifs;
    static std::ofstream ofs;

        //might or might not open the streams:
    OpenStreams(ifs,ofs,argc-1,argv);
        ........

        //here i would like to close the streams at the end of the program
        //or not (if they were not opened

    return 0;

}

谢谢!

【问题讨论】:

    标签: c++


    【解决方案1】:

    我真的不知道,也不想看。只需将其留给析构函数,如果需要,标准文件流将在销毁期间关闭文件。

    编辑:关于对象的生命周期和保证销毁...

    为了跟进我写给 Ben Voigt 的第二条评论,这是对对象生命周期的一个小测试:

    #include <cstdlib>
    #include <iostream>
    #include <string>
    
    struct test {
        std::string name;
        test( std::string const & name ) : name(name) {
            std::cout << "test " << name << std::endl;
        }
        ~test() { std::cout << "~test " << name << std::endl; }
    };
    
    void foo( bool exit ) {
        test t1( "1" );
        static test t2( "2" );
        test t3( "3" );
        if ( exit ) {
            std::exit(1);
        }
    }
    int main()
    {
        foo(false);
        std::cout << std::endl;
        foo(true);
    }
    

    以及执行的结果:

    test 1
    test 2
    test 3
    ~test 3
    ~test 1
    
    test 1
    test 3
    ~test 2
    

    可以看出,在第一次执行期间,foo 中的对象的构造与代码的顺序相同。但是当函数退出时,只有 auto 中的对象存储被销毁,而对象static 存储超过函数执行时间。

    在对 foo 的第二次调用中,auto 对象被重新创建,而 static 对象却没有像预期的那样,因为它是在之前的调用中创建的。因为foo 在第二次调用中调用exit(),所以foo 中的auto 对象不会被破坏。另一方面,static 对象被正确破坏。

    【讨论】:

    • +1 将其留给析构函数,但这可能需要将生命周期从 static 更改为自动。
    • 我正在使用以下命令打开流:ifs.open(fileName);
    • 它也会被析构函数关闭吗?
    • @Ben Voigt:我确实觉得 static 终身资格很奇怪,但在这种情况下这并不是真正的问题。由于函数是mainauto 变量或static 函数变量的生命周期基本相同:一旦 main 完成,本地 auto 对象将以相反的构造顺序销毁。然后静态对象将开始以相反的破坏顺序被破坏。这可能意味着早先在main 中创建的其他对象的销毁是在销毁流之前执行的,但这应该不是问题。
    • @Ben Voigt:...还请注意,让流具有static 存储持续时间是一个真正的优势。在调用abort()exit() 的情况下,static 对象肯定会被破坏,而auto 对象可能不会被破坏。
    【解决方案2】:

    为什么不在发出close() 之前使用is_open() 进行测试?

    【讨论】:

    • 实际上你最好遵循其他地方的建议让流析构函数处理这个问题,除非你绝对需要知道文件流在关闭时的状态,或者你打算重用流对象。一切顺利。
    【解决方案3】:

    不需要close 调用 - 流在它们被销毁时打开时会自行关闭。此外,那里的static 看起来很可疑。 main 只被调用一次,所以它在这里没有任何影响(除了在这里无关紧要的迂腐标准差异,我认为......绝对不是在所示的情况下)。

    也就是说,如果流未打开,您可以调用 close - close 如果未打开,将返回空指针。(我正在查看规范basic_filebuf&lt;&gt;::close - 文件流的 close 返回 void)。

    文件流也可以处理未打开的流:如果流未打开,它会设置failbit。您可以使用fail()(测试是否设置了故障位或坏位)进行检查。但是有is_open反正是用来测试流是否打开的,但是由于以上原因你不需要它。

    【讨论】:

    • 关于静态,在我的练习描述中建议将它们声明为静态,因为将它们声明为自动会产生分段错误。也许是因为我使用重定向到 std::cin\cout 和 rdbuf
    • @Mike 如果是这样的话,那一定是有史以来最糟糕的练习描述。
    • @Johanes:虽然起初我发现 funny 使用static 作为流,但如果main 中的任何代码可以exit() 是一个优势。通过具有static 存储持续时间,即使在exit() 的情况下,也可以保证流被销毁,而如果它们具有自动存储,它们将不会被销毁并因此关闭....再一次,如果他们已经解释了这一点在他们的课程中,如果他们确实提供了@Mike 建议我同意你的解释,我会留下深刻的印象并向教授表示敬意……可怕的教学方法。
    • @Mike:你知道,我最近没有读到好的恐怖故事,但你关于你的锻炼描述的陈述是合格的。如果将输入和输出流声明为自动变量会导致段错误,则存在非常严重的错误,正确的做法是找出并消除它。
    • @David 当我说“迂腐的标准差异”时,我就是这么想的。这样,当有人知道 Standardese 和 cmets 的深层含义时,我就不必改变我的答案 :) 见 *.com/questions/397075/…。我喜欢一个人可以链接到一些先前提出的 SO 答案,基本上任何出现的问题 :)
    【解决方案4】:

    只是不要将变量设为static,这样当main() 返回时它们会自动关闭。

    【讨论】:

      【解决方案5】:

      您可以使用is_open 方法来测试一个流是否已经打开,然后关闭它。

      【讨论】:

        【解决方案6】:

        为什么不在打开流之前设置一个标志。如果需要关闭流对象,请再次检查标志。

        更好的办法是在打开流时将打开的流对象传递给标志并使用它来关闭流。如果标志尚未初始化或为空,则不要关闭。

        【讨论】:

        • -1 用于通过使答案更不正确的编辑来详细说明已经不正确的答案。
        • 你看我在你写评论的时候正在编辑。无论如何 is_open 是应该使用的......我不知道。和平伙伴:)