Почему потоки в C++?

Поскольку Вы все знаете, что существуют библиотеки с помощью потоков такой как iostream и fstream.

Мой вопрос:

  • Почему потоки? Почему они не придерживались функций, подобных print, fgets и так далее (например)?

Они требуют своих собственных операторов << и >> но все, что они делают, могло быть реализовано в простых функциях как вышеупомянутый, также функция

printf("Hello World!");

намного более читаемо и логичен мне, чем

cout << "Hello World";

Я также думаю, что все те строковые абстракции в C++ вся компиляция вниз к (менее эффективной) стандартной функции звонят в двоичный файл.

8
задан oh boy 30 April 2010 в 05:58
поделиться

14 ответов

Потоки имеют лучшую безопасность типов.

Например, printf("%s", a); может пойти ужасно неправильно, если a - целое число. cout << a; не имеет этой проблемы.

Другая проблема заключается в том, что потоки лучше соответствуют методологии объектно-ориентированного проектирования.

Например, у вас есть простое приложение, которое пишет некоторый вывод, а затем вы хотите, чтобы вывод шел в файл, а не на консоль. При использовании вызовов C вам придется заменить все вызовы printf на вызовы fprintf и позаботиться о сохранении FILE* по пути. С потоками вы просто меняете конкретный класс используемого потока и все, большая часть кода остается неизменной, как например:

void doSomething(ostream& output)
{
   output << "this and that" << a;
}

doSomething(cout);
doSomething(ofstream("c:\file.txt"));
24
ответ дан 3 November 2019 в 12:09
поделиться

Во-первых, он позволяет вам использовать объектную модель C ++ для создания функций, которые не заботятся о том, пишут ли они в стандартный вывод, в файл или в сетевой сокет (если у вас есть сетевой сокет, производный от или поток ). Например.

void outputFoo(std::ostream& os)
{
  os << "Foo!";
}

int main()
{
  outputFoo(std::cout);

  std::ofstream outputFile("foo.txt");
  outputFoo(outputFile);

  MyNetworkStream outputSocket;
  outputFoo(outputSocket);
}

Аналогично для входных потоков.

Потоки также имеют преимущество при вводе и выводе объектов. Что произойдет, если вы захотите прочитать объект с помощью scanf ?

MyObject obj;
scanf("??", &obj); // What specifier to use? 

Даже если бы был соответствующий спецификатор, как scanf знал, как заполнять элементы объекта ? С потоками C ++ вы можете перегрузить оператор << и написать

MyObject obj;
std::cin >> obj;

, и он будет работать. Аналогично для std :: cout << obj , поэтому вы можете написать код сериализации объекта в одном месте и не беспокоиться об этом где-либо еще.

9
ответ дан 3 November 2019 в 12:09
поделиться

Потоки C ++ безопасны по типу. В C, если вы скажете:

double d = 1.23;
printf( "%d", d );

, вы не гарантированно получите сообщение об ошибке, даже если преобразование неверно.

Кажется, вы задаете очень простые вопросы по C ++. Какой учебник по C ++ не охватывает их?

7
ответ дан 3 November 2019 в 12:09
поделиться

Помимо типобезопасности и полиморфизма, потоки более переносимы. В некоторых системах printf с длинным значением требует "% d", а в некоторых системах - "% ld".

3
ответ дан 3 November 2019 в 12:09
поделиться

Потоки можно объединять в цепочку

cout << "hello" << " " << "world"
2
ответ дан 3 November 2019 в 12:09
поделиться

Кстати, C++ позволяет использовать printf. Так что если вам это нравится, используйте это.

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

Скажем, у вас есть сложный объект, который вы хотите иметь возможность записывать в консоль вывода, в файл журнала и во всплывающее окно отладки. Собираетесь ли вы написать три функции, которые делают почти одно и то же, или вы напишете одну функцию, которой передадите поток вывода (y)?

.
1
ответ дан 3 November 2019 в 12:09
поделиться

stringstream безопаснее, чем snprintf/sscanf, поскольку полностью исключает возможность переполнения буфера (даже "graceful failures").

0
ответ дан 3 November 2019 в 12:09
поделиться

На самом деле

cout << "Test: " << test << endl;

кажется мне гораздо более интуитивным, чем

printf("Test: %d\n", test);

Если вы никогда раньше не видели printf, вы ни за что не поймете, что он делает.

В любом случае

print "Test: " + test

(в нескольких языках, включая Python :( ) имеет гораздо больше смысла :)

1
ответ дан 3 November 2019 в 12:09
поделиться

printf для одного типа не безопасен. Интерфейс cout также более общий, что позволяет многое, недоступное в версии printf. Отличным примером является то, что ваш оператор потока для ваших типов, если вы все делаете правильно, ссылается на std :: ostream как на поток, а не на cout. Таким образом, вы можете изменить место назначения вывода, просто используя другой поток. Чтобы сделать это с помощью printf, вам нужно выполнить множество зависимых от платформы перезаписей выходных дескрипторов.

Я также думаю, что все эти строковые абстракции в C ++ компилируются до (менее эффективных) стандартных вызовов функций в двоичном формате.

Думайте сколько хотите. Пока вы на самом деле не проверите свое предположение, ваше мнение не будет иметь большого значения.Кроме того, вам нужно учитывать потерю абстракции, что обычно намного важнее в современной разработке программного обеспечения.

5
ответ дан 3 November 2019 в 12:09
поделиться

Я до сих пор использую printf, главным образом потому, что с его помощью легко контролировать выходной формат.

Для меня безопасность типов не является здесь главным преимуществом, потому что ее можно легко обнаружить с помощью тестирования, учитывая тот факт, что консольную программу гораздо легче тестировать, чем приложения на основе пользовательского интерфейса или веб-приложения. Если вы не проводите тестирование, более серьезные ошибки могут в любом случае преодолеть проверку во время компиляции.

Я также не согласен с другой причиной, по которой поток заявок более гибкий благодаря взаимозаменяемости. Это эквивалентно рекомендации использовать fprintf (fout, ...) для взаимозаменяемости. Если вам нужно перенаправить вывод, используйте pipe. Если вы находитесь в библиотеке, почему бы вам просто не вернуть строку и позволить вызывающей стороне решить, куда она идет?

0
ответ дан 3 November 2019 в 12:09
поделиться

Синтаксис, подобный потоку, с оператором << и оператором >> обеспечивает удобную конкатенацию.

printf("%d%d%d%d%d", a, b, c, d, e);

vs

cout << a << b << c << d << e;

Более того, в первом подходе нужно всегда думать о типе, в то время как в потоковом подходе тип указывать не нужно.

1
ответ дан 3 November 2019 в 12:09
поделиться

C++ IOStreams являются до смешного неэффективными (в большинстве известных мне реализаций). Часто это не является проблемой, но когда это так, библиотека в основном бесполезна. Также верно подмечено, что синтаксис неинтуитивен (и очень, очень многословен). Библиотека сложна, и ее неоправданно трудно расширять. Она также не очень гибкая. В сравнении с чем-то вроде STL, IOStreams действительно выглядит как страшный сон. Но она здесь, и мы застряли с ней.

Причина, по которой он здесь, и причина, по которой он выглядит так, как выглядит, заключается в том, что он был разработан раньше, до того, как C++ стал зрелым языком. До того, как у нас появились десятилетия опыта, говорящие нам, что является, а что не является хорошим дизайном библиотек. До того, как кто-то действительно знал, какие есть варианты.

C++ нужна была библиотека ввода-вывода, которая была бы лучше, чем у C. И в некоторых важных отношениях, IOStreams C++ лучше. Они безопасны с точки зрения типов и расширяемы, как уже говорили другие. Реализовав один оператор, я могу вывести пользовательский класс. Этого нельзя сделать с помощью printf. Мне также не нужно беспокоиться о том, что я неправильно определю спецификаторы формата и распечатаю мусор из-за отсутствия безопасности типов.

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

Библиотека IOStreams - это компромисс между:

  • чем-то более безопасным и расширяемым, чем stdio.h
  • чем-то эффективным
  • чем-то хорошо продуманным и интуитивно понятным
  • библиотекой, которая действительно существовала во времена стандартизации C++. (им нужно было добавить что-то, поэтому им пришлось выбирать между кандидатами, которые реально существовали в то время)

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

2
ответ дан 3 November 2019 в 12:09
поделиться

Потоки работают с шаблонами, тогда как printf/scanf - нет.

0
ответ дан 3 November 2019 в 12:09
поделиться

Еще одно преимущество потоков состоит в том, что их можно расширять. С потоками вы можете настроить свои определяемые пользователем классы так же, как и встроенные типы:

class foo { ... };

ostream &operator<<(ostream &ostr, const foo &f)
{
    ostr << ... how you want to print a foo ...;
    return ostr;
}

И теперь вы можете печатать foo, как и все остальное:

int n = ...
foo f = ...

cout << n << ": " << f << endl;
2
ответ дан 3 November 2019 в 12:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: