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

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

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

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

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


person calccrypto    schedule 05.06.2011    source источник
comment
Вы ищете какой-то поток черной дыры, который вы тоже можете записать, но который ничего не делает с данными? Я полагаю, вы могли бы получить его, но большинство людей просто проверяли бы, что указатель потока не равен NULL, прежде чем пытаться писать в него.   -  person Codie CodeMonkey    schedule 05.06.2011
comment
Что означает "but destroyed if not"? Почему бы вам не написать псевдокод, чтобы прояснить свой вопрос?   -  person Nawaz    schedule 05.06.2011
comment
как в: мне все равно, куда он идет, пока он не появляется там, где пользователь мог бы проверить, например, файл или терминал   -  person calccrypto    schedule 05.06.2011
comment
Так что в основном ostream-эквивалент /dev/null   -  person Chris Eberle    schedule 05.06.2011
comment
почему отрицательное голосование и закрытые голоса ??   -  person calccrypto    schedule 05.06.2011
comment
@calc: Я думаю, не понизил голос: потому что вопрос не совсем ясен. Как говорит @Nawaz, что значит, кроме уничтожения, если не означает?   -  person Xeo    schedule 05.06.2011
comment
@calc: см. мой ответ еще раз, отредактировал его.   -  person Xeo    schedule 05.06.2011
comment
Этот вопрос закрыт как точный дубликат, но не дается ссылка на то, что он является дубликатом. Можем ли мы получить ссылку на другой вопрос?   -  person cheshirekow    schedule 05.06.2012


Ответы (3)


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

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, он автоматически устанавливает плохой бит и молча игнорирует любые записи:

// 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() -- хороший бит, если sb не является нулевым указателем, иначе плохой бит.

Что произойдет, если установить 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
person Xeo    schedule 05.06.2011
comment
Спасибо за хороший ответ. Есть ли разница в os.good() для двух схем? С std::ostream os(nullptr) assert(os) не получится, а с std::ostream os(&nullobj) assert(os) нет? Я просто предполагаю. - person Hugues; 19.11.2014

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

person rlduffy    schedule 05.06.2011
comment
... вы можете сделать то же самое, не открывая эти специальные файлы. Технически все, что вам нужно сделать, это принять аргументы в вашей перегрузке <<, а затем просто ничего с ними не делать. - person Chris Eberle; 05.06.2011
comment
это правда. но пользователю все равно придется сначала создать поток - person calccrypto; 05.06.2011
comment
и как бы я его использовал? std::ostream stream = NUL и std::ostream stream = std::ostream(NUL) не работают как параметры - person calccrypto; 05.06.2011
comment
@calc: Если вам нужен непереносимый, вы можете попробовать std::ostream stream("/dev/null") в Linux / Unix. - person Xeo; 05.06.2011
comment
Нет-нет, все дело в том, что вы делаете СОБСТВЕННЫЙ ostream (называемый blackhole или что-то в этом роде), который при записи просто игнорирует все данные. Это не имеет ничего общего с нулевым указателем. - person Chris Eberle; 05.06.2011

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

void data(std::ostream & stream = ostream(NULL,false)){
    stream << "DATA" ;
}
person Ali1S232    schedule 05.06.2011
comment
-1, это не сработает. Временный поток может быть привязан только к ссылке const T&, но запись в постоянный поток невозможна. Я думаю, что MSVC позволяет это как расширение, но... - person Xeo; 05.06.2011
comment
он работает и компилируется с использованием vc++, но, похоже, имеет некоторые проблемы с gcc. - person Ali1S232; 05.06.2011