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

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

8 голосов
/ 30 апреля 2010

Как вы все знаете, есть библиотеки, использующие потоки, такие как iostream и fstream.

Мой вопрос:

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

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

printf("Hello World!");

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

cout << "Hello World";

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

Ответы [ 14 ]

24 голосов
/ 30 апреля 2010

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

Например, 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"));
9 голосов
/ 30 апреля 2010

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

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 ++ вы можете перегрузить operator<< и написать

MyObject obj;
std::cin >> obj;

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

7 голосов
/ 30 апреля 2010

C ++ потоки являются типобезопасными. В Си, если вы говорите:

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

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

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

5 голосов
/ 30 апреля 2010

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

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

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

3 голосов
/ 30 апреля 2010

Помимо того, что типы безопасны и полиморфны, потоки более переносимы. В некоторых системах printf с long требует «% d», а в некоторых системах требуется «% ld».

2 голосов
/ 01 мая 2010

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

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

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

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

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

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

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

2 голосов
/ 30 апреля 2010

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

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 голосов
/ 30 апреля 2010

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

cout << "hello" << " " << "world"
1 голос
/ 30 апреля 2010

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

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

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

1 голос
/ 30 апреля 2010

На самом деле

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

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

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

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

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

print "Test: " + test

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...