【问题标题】:Redirecting std::cout重定向 std::cout
【发布时间】:2011-01-20 22:02:29
【问题描述】:

我需要一个在其对象的生命周期内将一个 ostream 重定向到另一个 ostream 的类。经过一番修补,我想出了这个:

#include <iostream>
#include <fstream>


class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mRedirect(inRedirect)
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::ostream & mRedirect;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    return 0;
}

它似乎工作正常。然而,奇怪的是,在 构造函数和析构函数中都重复了以下行:

mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));

我认为这是正确的,但我想与 SO 社区进行验证。您能在这段代码中发现任何错误或危险吗?

编辑

使不可复制。

【问题讨论】:

  • +1 - 应该是正确的 - 但如果您根据通用 std::ostream 实现逻辑而不是直接调用 std::cout 会更好。
  • @Billy ONeal:ScopedRedirect 不是已经根据通用 ostream 实现了吗? std::cout 仅在示例中使用。
  • 我并不是说你的课不好或不正确。我只是说最好将输出发送到您希望它实际去的地方,而不是在事后重定向它的去向。也就是说,我的意思是应该重构依赖于指向任何特定位置的 std::cout 的代码,而不是更改 cout 指向的位置。
  • @Billy ONeal:啊,我明白了。我绝对同意你的看法。我需要这个类的原因是因为我想关闭由大型遗留代码库产生的调试消息。这是一个(希望是)临时修复。

标签: c++


【解决方案1】:

这些行相同的原因是因为您所做的是交换 缓冲区。 (也就是说,您通过将原始缓冲区与重定向缓冲区交换来“重定向”;恢复就是交换回来。)

虽然这可能会为您提供与输出流相关的预期效果,但这是不正确的,因为重定向流现在输出到其他地方。 To redirect 表示取一个流并将其输出到其他地方;请注意,这不会影响“其他地方”。

您的课程不是重定向;实际上,它应该真正命名为ScopedStreamSwap。例如,试试这个:

#include <iostream>
#include <fstream>

class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mRedirect(inRedirect)
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::ostream & mRedirect;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;

        // oops:
        filestream << "also to the file, right?...nope" << std::endl;
        filestream << "ah, why am i on the screen?!" << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    // in main, return 0 is implicit, if there is no return statement;
    // helpful to keep in mind in snippets and short things
}

你想要的是这个:

#include <iostream>
#include <fstream>

class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mOldBuffer(inOriginal.rdbuf(inRedirect.rdbuf()))
    { }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mOldBuffer);
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::streambuf * mOldBuffer;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;

        // yay:
        filestream << "also to the file, right?...yes" << std::endl;
        filestream << "i am not on the screen" << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    return 0;
}

【讨论】:

  • +1 表示有趣且内容丰富,以及有趣的示例文本。
  • 感谢您发布有效的修复程序。我开始意识到我只是在交换缓冲区,但奇怪的是我无法以不同的方式做到这一点。由于某种原因,语法让我很困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-18
  • 1970-01-01
  • 2023-03-28
  • 2012-06-16
相关资源
最近更新 更多