50

有没有办法创建一个基本上不做任何事情的 ostream 实例?

例如 :

std::ostream dummyStream(...);
dummyStream << "Nothing will be printed";

我可以只创建一个 ostringstream,但数据将被缓冲(我真的不想用它们做任何事情,所以它增加了无用的开销)。

任何想法 ?

[编辑]找到适合我需要的相关问题。但是,我认为有一个答案来说明如何使用标准 c++ 创建一个有效的(无坏位)输出流可能会很有用。

4

6 回答 6

74

您需要一个自定义的流缓冲区。

class NullBuffer : public std::streambuf
{
public:
  int overflow(int c) { return c; }
};

然后,您可以在任何 ostream 类中使用此缓冲区

NullBuffer null_buffer;
std::ostream null_stream(&null_buffer);
null_stream << "Nothing will be printed";

streambuf::overflow是当缓冲区必须将数据输出到流的实际目的地时调用的函数。上面的NullBuffer类在调用溢出时什么都不做,所以任何使用它的流都不会产生任何输出。

于 2012-08-06T10:38:49.990 回答
36

如果这是为了禁用日志输出,您dummyStream仍然会导致评估参数。如果您想在禁用日志记录时最小化影响,您可以依赖条件,例如:

#define debugStream \
    if (debug_disabled) {} \
    else std::cerr

因此,如果您有如下代码:

debugStream << "debugging output: " << foo() << std::endl;

debug_disabled如果为真,则不会评估任何参数。

于 2012-08-06T10:46:56.050 回答
4

新流类的基本方法是:

  1. std::streambuf从;派生一个类
  2. 覆盖该类中的虚函数。这是真正的工作完成的地方。在您的情况下,空实现应该足够好。
  3. 从一个成员派生一个类std::ostream,即您的 streambuf 类。
  4. 您的流类的构造函数应该将指向该成员的指针转发给 std::ostream 的基本构造函数。

不过,恐怕您不会摆脱格式化步骤。

希望这能给您一些指示;抱歉,我没有时间将其扩展为完整的答案。

更新:有关详细信息,请参阅约翰的答案

于 2012-08-06T10:48:01.193 回答
1

对于日志消息的运行时可控重定向,结合了 john 和 Sjoerd 思想的自包含解决方案:

class DebugStream {
private:
    class NullStream : public std::ostream {
    private:
        class NullBuffer : public std::streambuf {
        public:
            int overflow(int c) override { return c; }
        } buffer_;
    public:
        NullStream() : std::ostream(&buffer_) {}
    } null_;

    std::ostream &output_;
    bool enabled_;

public:
    DebugStream(std::ostream &output = std::cout) : output_(output), enabled_(false) {}
    void enable(const bool enable) { enabled_ = enable; }

    template <typename T> std::ostream& operator<<(const T &arg) {
        if (enabled_) return output_ << arg;
        else return null_ << arg;
    }
};

extern DebugStream debug_stream;
#define TRACE_ENABLE(x) debug_stream.enable(x)
#define TRACELN(x) debug_stream << x << std::endl
#define TRACE(x) debug_stream << x

然后你可以做类似的事情:

TRACELN("The value of x is " << x " and the value of y is " << y);

#define使用跟踪宏将跟踪语句完全从发布版本中删除到空语句也很容易。

不过,您仍然需要在debug_stream某个全局位置定义。

于 2020-06-03T22:50:57.473 回答
0

如果您担心调试器的开销,那么您可以编写一个非常简单的代码来取消编译时的调试消息。这就是我用于我的 c++ 程序的内容。

#include <iostream>
#define DEBUGGING // Define this in your config.h or not.
#ifdef DEBUGGING
/*
 * replace std::cout with your stream , you don't need to
 * worry about the context since macros are simply search
 * and replace on compilation.
 */
#define LOG_START std::cout <<
#define LOG_REDIR <<
#define LOG_END   << std::endl;
#else
#define LOG_START if(0){(void)
#define LOG_REDIR ;(void)
#define LOG_END   ;}
#endif // DEBUGGING

int main(){
LOG_START "This is a log message " LOG_REDIR "Still a log message." LOG_END;
return 0;
}

现在在制作项目时,检查用户是否要禁用日志记录,如果是,只需取消定义 DEBUGGING 宏或您选择检查的任何宏。

现在您的代码将由编译器优化,因为当任何内容无效时,它不会包含在生成的二进制文件中(大部分时间),从而使二进制文件准备就绪。

于 2018-07-09T02:21:53.943 回答
-1

我需要一个 ostream 类型的空流,所以我做了这样的事情:

struct NullStream: public stringstream {
   NullStream(): stringstream() {}
};

template<typename T>
void operator<<(const NullStream&, const T&) {}

申请代码:

NullStream ns;
ostream &os = ns;
os << "foo";

真正的问题是我继承但不关心的所有公共方法,所以我只是懒得重写它们。

于 2018-02-02T15:58:17.877 回答