Подтвердить что ты не робот

Должен ли я переключиться на потоки ввода-вывода С++?

Я никогда не использовал много потоков ввода-вывода С++ и всегда выбирал то, что знаю. т.е. функции printf.

Я знаю, что есть некоторые преимущества использования потоков ввода-вывода, но я ищу несколько советов из сообщества stackoverflow, чтобы помочь мне (или убедить меня) переключиться. Потому что я все еще предпочитаю printf, и я думаю, что стиль printf намного проще читать и быстрее печатать.

Я все еще хотел бы быть знаком с ним, даже если я все еще продолжаю использовать printf.


Изменить. Интересно, что стиль кодирования Google С++ запрещает использование потоков, кроме ведения журнала. См.: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

Струйные

Использовать потоки только для ведения журнала. Определение: потоки являются замена для printf() и scanf().

Плюсы. С потоками вам не нужно знать тип объекта, который вы печать. У вас нет проблем с форматированием строк, а не сопоставляя список аргументов. (Хотя с gcc у вас нет этого проблема с printf.) В потоках есть автоматические конструкторы и деструкторы, которые открывают и закрывают соответствующие файлы.

Минусы. Потоки затрудняют выполнение таких функций, как pread(). Некоторые форматирование (в частности, идиома строки общего формата%. * s) трудно, если не невозможно, эффективно использовать потоки без используя printf-подобные хаки. Потоки не поддерживают переупорядочение операторов (директива% 1s), которая полезна для интернационализации.

Решение. Не используйте потоки, кроме случаев, когда это необходимо для ведения журнала. интерфейс. Вместо этого используйте printf-подобные подпрограммы.

Существуют различные плюсы и минусы использования потоков, но в этом случае, поскольку во многих других случаях согласованность превзошла дискуссию. Не использовать потоки в вашем коде.

Расширенная дискуссия

В этом вопросе шла дискуссия, поэтому это объясняет большая глубина. Напомним принцип "Единственный путь": мы хотим убедитесь, что всякий раз, когда мы выполняем определенный тип ввода-вывода, код выглядит то же самое во всех этих местах. Из-за этого мы не хотим позволять пользователи могут выбирать между использованием потоков или использованием printf plus Чтение/запись/и т.д.. Вместо этого мы должны согласиться на том или ином. Мы сделали исключение для ведения журнала, потому что это довольно специализированный приложения и по историческим причинам.

Сторонники потоков утверждают, что потоки - это очевидный выбор из двух, но вопрос на самом деле не так ясен. Для каждого преимущества потоков, которые они указывают, есть эквивалент недостаток. Самое большое преимущество в том, что вам не нужно знать тип объекта, подлежащего печати. Это справедливый вопрос. Но, есть недостаток: вы можете легко использовать неправильный тип, и компилятор не предупредит вас. Легко сделать такую ​​ошибку не зная при использовании потоков.

cout << this;  // Prints the address 
cout << *this;  // Prints the contents 

Компилятор не генерирует ошибку, поскольку < < < был перегружен. Мы препятствуем перегрузке именно по этой причине.

Некоторые говорят, что форматирование printf является уродливым и трудночитаемым, но потоки часто не лучше. Рассмотрим следующие два фрагмента, как с такой же опечатка. Что легче обнаружить?

cerr << "Error connecting to '" << foo->bar()->hostname.first
     << ":" << foo->bar()->hostname.second << ": " << strerror(errno);
fprintf(stderr, "Error connecting to '%s:%u: %s",
      foo->bar()->hostname.first, foo->bar()->hostname.second,
      strerror(errno)); 

И так далее и т.д. для любой проблемы, которую вы можете вызвать. (Вы могли бы утверждать: "Вещи быть лучше с правые обертки", но если это верно для одной схемы, не правда ли это для другого? Кроме того, помните, что цель состоит в том, чтобы сделать язык меньше, не добавляйте еще больше машин, которые кто-то должен изучить.)

Любой путь привел бы к разным преимуществам и недостаткам, и нет четкого решения. Доктрина простоты мандаты мы урегулируем на одном из них, хотя, и решение большинства был на printf + read/write.

4b9b3361

Ответ 1

Я сам не большой пользователь потоков, поэтому я расскажу только о том, что я думаю о них. Это действительно субъективно, я пойму, если мой ответ будет проголосован за удаление.

  • Мне нравится: однородность

У меня может быть enum, a class или что-то еще, что делает мой пользовательский тип печати пригодным всегда, обеспечивая тот же operator<< рядом с моим типом:

std::ostream &operator<<(std::ostream &, const MyType &);

Вы можете спросить себя, может ли тип печатать, но никогда, как его можно печатать.

  • Мне нравится: абстракция

Очевидно, что невероятно просто обеспечить "потоковые возможности" для определенного пользователем типа. Это также отлично, чтобы обеспечить нашу собственную реализацию потока и обеспечить прозрачность в существующем коде. Как только ваш operator<< будет соответствующим образом определен, запись на стандартный вывод, буфер памяти или файл тривиально изменчивы.

  • Мне не нравится: форматирование

Я всегда думал, что iomanip - беспорядок. Я ненавижу писать такие вещи, как (я просто бросаю случайных манипуляторов здесь):

std::cout << std::left << std::fixed << std::setprecision(0) << f << std::endl;

Я думаю, что было намного проще с printf, но Boost.Format здесь полезен.

Ответ 2

Используйте boost:: format. Он получил лучшее из обоих миров.

Ответ 3

Огромное преимущество, которое предлагает iostreams, - безопасность. printf() является неотъемлемой небезопасной функцией. Не только это, но и тривиально, чтобы перегрузить < для ваших собственных типов, тогда как реалистично невозможно расширить printf() - у этого есть дополнительное преимущество мгновенной перегрузки для вывода на файлы, а также все, что связано с потоком. В сочетании они делают printf() непригодным для использования в высококачественном коде. Я также заметил абсолютно никакой разницы в производительности, хотя я вижу, что многие люди публикуют о том, насколько они медленны.

Ответ 4

@Мат, я с тобой. Я всегда ненавидел потоки. Конечно, я могу их использовать. Заставьте их делать все, что я хочу. Но мне нравится printf, потому что я предпочитаю синтаксис.

Я даже написал strprintf, который работал точно так же, как sprintf, за исключением возврата std::string вместо записи в буфер char.

Но постепенно, без колебаний, я почти полностью прекратил использовать sprintf. Потому что, просто говоря, я пишу слишком чертовски много ошибок, и мне становится больно и надоело повторять ту же ошибку снова и снова. stringstream тип безопасности спасает меня от себя.

Ошибки, о которых я говорю для меня, представлены в двух формах, главным образом:

  • Я выбрал неправильное магическое число для моего выходного буфера. Скажем, я придумал char buf_[256], чтобы отформатировать кое-что. Ну, точно так же, как Билл Гейтс знаменито объяснил, что "256 КБ памяти должно быть достаточно для кого-то", я ошибаюсь на низкой стороне, чтобы ловить глаз. С другой стороны, что я буду делать? char buf_[1024*64]? Экстрим, но вы понимаете. Там нет совершенного волшебного числа. Вы либо подвергаете себя большему количеству сбоев, либо теряете память.

  • I sprintf - задал строку, но отправил ей float. Делайте это все время. Ну, не все время. За каждые 100 вызовов sprintf я, вероятно, делаю это один или два раза. Для производственного кода это много.

С потоками ни один из них не может произойти. Поэтому я использую потоки сейчас, и мой код никогда не сбой. Ну... там, во всяком случае.

Некоторые скажут, что потоки медленнее, чем sprintf. Может быть. Ради спора, я даже соглашусь с этим. Не имеет значения, хотя. Я работаю на серверах на фондовом рынке реального времени, которые обрабатывают 3 миллиона сообщений в секунду в течение всего дня. И у меня никогда не было проблемы со скоростью потоков. Может быть, это немного медленнее, но у меня есть большая рыба, чтобы жарить.

Ответ 5

Вы не можете расширять printf с помощью спецификаторов нового формата для обработки ваших собственных типов.

Ответ 6

Вы получаете больше защиты от ошибок типов с потоками ввода-вывода С++, но они медленнее. Таким образом, в основном это зависит от того, насколько важна производительность.

Потоки ввода-вывода также являются полиморфными, в отличие от функций C stdio пользователь потока не должен знать, подключен ли он к консоли, файлу или какой-либо другой логике. Но это не важно для большинства приложений.

Ответ 7

Я переключился на iostreams после того, как я узнал С++ 10 лет назад. Несколько лет назад я был убежден, что это плохой выбор, поэтому я переключился обратно. Я не пожалел об этом. Для хорошего программиста на С++ вам нужно знать оба.

Руководство по стилю Google С++ предпочитает использовать printf/sprint/snprint поверх iostreams. Он говорит, что использовать iostreams только для ведения журнала.

Что касается преимуществ iostreams:

  • Тип безопасности. Компилятор (gcc) может обнаруживать ошибки типа, а также все инструменты статического анализа. Даже есть ошибка типа, можно легко обнаружить ошибку при распечатке.
  • расширяемость. Да, iostreams имеют перегрузку, но все члены данных в конечном итоге переходят к типам POD.
  • Отсутствие переполнения буфера. Используйте snprintf для устранения проблемы с размером буфера.

Теперь приходят преимущества sprintf:

  • Гораздо лучше читаемость. "Record(%d): %s\n" намного легче читать, чем os << "Record(" << i << ") " << msg << endl;
  • Производительность. Если вы делаете много вещей iostreams, изменение их значительно повышает производительность. Однажды я работал над библиотекой, которая использует stringstream для преобразования int/double в строки. Я заменил sprintf, и производительность значительно улучшилась (есть много вызовов в процедуру преобразования). Для записи boost:: format имеет еще худшую производительность.

Мое заключение заключается в том, что использовать iostreams бесплатно. Я использую его для чтения буфера памяти или иногда в буфер памяти. Для других работ я использую обычную функцию C.

Ответ 8

Чтобы следить за ответом Ноя, библиотека форматирования форматирования допускает несколько разных синтаксисов, включая синтаксис типа printf. Он работает, перегружая оператор%, и поэтому сначала кажется немного странным. Но, что-то, что мне нравится, это позволяет вам повторно использовать аргументы. Например

cout << format("%1% %2% %1%") % 1 % 2 << endl;

напечатает

1 2 1

Это довольно универсально, и если вы можете привыкнуть к знакам% повсюду, вы получите лучшее из обоих миров. Насколько я согласен, стиль printf часто намного проще.

http://beta.boost.org/doc/libs/1_43_0/libs/format/doc/format.html