Независимая от платформы /dev/null в C++

Возможный дубликат:
Реализация no-op std::ostream

Есть ли потоковый эквивалент NULL в C++? Я хочу написать функцию, которая принимает поток, если пользователь хочет, чтобы внутренний вывод был куда-то, но если нет, вывод идет в какое-то поддельное место

void data(std::stream & stream = fake_stream){
    stream << "DATA" ;
}

я хочу быть в состоянии сделать выбор data() или же data(std::cout)

3 ответа

Решение

Редактировать: взято из @Johannes Schaub - письмо Литба здесь с небольшими изменениями:

template<typename Ch, typename Traits = std::char_traits<Ch> >
struct basic_nullbuf : std::basic_streambuf<Ch, Traits> {
     typedef std::basic_streambuf<Ch, Traits> base_type;
     typedef typename base_type::int_type int_type;
     typedef typename base_type::traits_type traits_type;

     virtual int_type overflow(int_type c) {
         return traits_type::not_eof(c);
     }
};

// convenient typedefs
typedef basic_nullbuf<char> nullbuf;
typedef basic_nullbuf<wchar_t> wnullbuf;

// buffers and streams
// in some .h
extern std::ostream cnull;
extern std::wostream wcnull;

// in a concrete .cpp
nullbuf null_obj;
wnullbuf wnull_obj;
std::ostream cnull(&null_obj);
std::wostream wcnull(&wnull_obj);

Используйте те:

void data(std::ostream& stream = cnull){
  // whatever...
}

Теперь, это выглядит круто и все, но следующее намного короче и работает, потому что, если нулевой указатель предоставляется конструктору ostream, он автоматически устанавливает badbit и молча игнорирует любые записи:

// in .h
extern std::ostream cnull;
extern std::wostream wcnull;

// in .cpp
std::ostream cnull(0);
std::wostream wcnull(0);

Стандарт гарантирует, что это работает, начиная с 27.6.2.2 [lib.ostream.cons] p1 который описывает конструктор ostream это берет указатель на streambuf:

Эффекты: Создает объект класса basic_ostream, присваивая начальные значения базовому классу, вызывая basic_ios<charT,traits>::init(sb),

Соответствующая функция из basic_ios, 27.4.4.1 [lib.basic.ios.cons] p3:

void init(basic_streambuf<charT,traits>* sb);
Постусловия: постусловия этой функции указаны в таблице 89:

Важная строка из таблицы 89:

rdstate () - goodbit, если sb не является нулевым указателем, иначе badbit.

Что произойдет, если badbit установлен описан под 27.6.2.6 [lib.ostream.unformatted]:

Каждая неотформатированная выходная функция начинает выполнение с создания объекта класса sentry, Если этот объект возвращает true при преобразовании в значение типа bool, функция пытается сгенерировать запрошенный вывод.

Это означает, что в случае sentry ложно, это не так. Вот как sentry превращается в bool, взято из 27.6.2.3 [lib.ostream::sentry] p3 & p5:

3) Если после какой-либо подготовки os.good() является true, ok_ == true иначе, ok_ == false,

5) operator bool();
Эффекты: возвращает ok_.

(ok_ является членом ostream::sentry типа bool.)


Обратите внимание, что эти кавычки все еще присутствуют в C++11, просто в разных местах. По порядку появления в этом ответе:

  • 27.6.2.2 [lib.ostream.cons] p1 => 27.7.3.2 [ostream.cons] p1
  • 27.4.4.1 [lib.basic.ios.cons] p3 => 27.5.5.2 [basic.ios.cons]
  • Таблица 89 => Таблица 128
  • 27.6.2.6 [lib.ostream.unformatted] => 27.7.3.7 [ostream.unformatted] p1
  • 27.6.2.3 [lib.ostream::sentry] p3 & p5 => 27.7.3.4 [ostream::sentry] p4 & p5

Файл Linux /dev/null - это черная дыра, которую вы ищете. В Windows есть устройство под названием NUL:. Я никогда не пытался открыть этот файл, но я использовал его из командной строки

Вы можете попробовать ostream(NULL,false), первый вход - целевой выход, и я не знаю, что означает второй ввод exaclty, но после отслеживания кода кажется, что ostream просто некуда писать, вызывая operator << просто игнорируется ostream. Я имею в виду, что при первом вызове состояние меняется на плохое, и после этого оно всегда игнорирует входные данные из-за состояния потока, поэтому вы можете использовать следующий код:

void data(std::ostream & stream = ostream(NULL,false)){
    stream << "DATA" ;
}
Другие вопросы по тегам