С++ Streams против C-style IO?
Я программировал некоторый С++ для небольшого проекта хобби, когда заметил, что я использую операции типа C для доступа к IO (printf
, fopen
и т.д.).
Считается ли "плохой практикой" задействовать функции C в проектах на С++? В чем преимущества использования потоков по доступу IO C-стиля?
Ответы
Ответ 1
Это горячая тема.
Некоторые люди предпочитают использовать С++ IO, поскольку они безопасны по типу (у вас не может быть расхождения между типом объекта и типом, указанным в строке формата) и более естественно протекать с остальной частью С++ способ кодирования.
Однако есть также аргументы для функций C IO (мои личные фавориты). Некоторые из них:
- Они легче интегрируются с локализацией, так как вся строка для локализации не разбивается на меньшие строки, а с некоторой реализацией локализатор может изменить порядок введенного значения, переместить их в строку,...
- Вы можете непосредственно увидеть формат текста, который будет написан (это может быть очень сложно с потоковыми операторами).
- Поскольку нет вставки и только один экземпляр функции
printf
, сгенерированный код меньше (это может быть важно во встроенной среде).
- Быстрее, чем функция С++ в некоторой реализации.
Лично я бы не счел плохую практику использовать C-поток в коде С++. Некоторые организации даже рекомендуют использовать их поверх потока С++. То, что я считаю плохим, - использовать как в одном проекте. Консистенция - вот ключ, который я думаю.
Как отмечали другие, в относительно большом проекте вы, вероятно, не использовали бы их напрямую, но вы бы использовали набор функций-оболочек (или классов), которые лучше всего соответствовали бы вашему стандарту кодирования и вашим потребностям (локализация, тип безопасности,...). Вы можете использовать один или другой интерфейс ввода-вывода для реализации этого интерфейса более высокого уровня, но вы, вероятно, будете использовать только один.
Изменить: добавление некоторой информации о преимуществах семейства функций форматирования printf
, относящихся к локализации. Обратите внимание, что эта информация действительна только для некоторой реализации.
Вы можете использовать %m$
вместо %
, чтобы ссылаться на параметр по индексу, а не ссылаться на них последовательно. Это можно использовать для изменения порядка в форматированной строке. Следующая программа напишет Hello World!
на стандартный вывод.
#include <stdio.h>
int main() {
printf("%2$s %1$s\n", "World!", "Hello");
return 0;
}
Рассмотрим перевод этого кода на С++:
if (nb_files_deleted == 1)
stream << "One file ";
else
stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";
Это может быть очень сложно. С printf
(и библиотекой типа gettext
для обработки локализации) код не смешивается со строкой. Таким образом, мы можем передать строку команде локализации и не будем обновлять код, если на каком-либо языке есть специальный случай (на некотором языке, если количество объектов равно 0, вы используете множественную форму на другом языке, существует три формы для сингулярных, одна, когда есть два объекта и множественная форма,...).
printf (ngettext ("One file removed from directory \"%2$s\"",
"%1$d files removed from directory \"%2$s\"",
n),
n, dir);
Ответ 2
printf
и друзья ужасно опасны по сравнению с <iostream>
и не могут быть расширены, плюс, конечно, fopen
, а друзья не имеют RAII, а это означает, что, если вы не доказали с профилировщиком, что вам определенно нужно (что вы доказали, что существует на вашей платформе и в вашем коде), вам нужно быть идиотом до printf
.
Изменить: Локализация - это интересная вещь, которую я не рассматривал. Я никогда не локализовал какой-либо код и не могу прокомментировать относительную локализационную способность printf
и <iostream>
Ответ 3
Для небольшого проекта для хобби я, вероятно, поеду с более безопасными потоками С++ io.
Забавно, я никогда не видел нетривиального реального проекта, который использует любой из них. Во всех случаях мы использовали некоторые абстракции, построенные поверх родного OS API для ввода-вывода.
Ответ 4
Ничто не может считаться плохой практикой, если оно имеет определенную цель. Я имею в виду, что если IO является узким местом в программе, то да, IO C-style работает быстрее, чем С++ IO. Но если это не так, я бы пошел с потоком С++ stream. Cuz это cuter:)
Ответ 5
<сильные > Преимущества
- Тип безопасности: типы аргументов потоковых операций С++ проверяются во время компиляции, а аргументы
printf
передаются через ...
, вызывая поведение undefined, если они не соответствуют форматированию.
- Управление ресурсами: объекты потока С++ имеют деструкторы для закрытия дескрипторов файлов, свободных буферов и того, что у вас есть. C потоки требуют, чтобы вы не забыли позвонить
fclose
.
Недостатки
- Производительность: это, конечно, зависит от реализации, но я нашел форматирование с потоками С++ значительно медленнее, чем эквивалентное форматирование
printf
.
Ответ 6
Для этого вам не нужно сначала преобразовывать объекты С++ (особенно string
s) в C-совместимые формы.
Ответ 7
IMHO, настоящий программист на С++ пытается делать что-то в идиоматическом С++-способе; программируемый программист C пытается цепляться за старые способы делать вещи. Это связано с читабельностью и согласованностью.
Ответ 8
Считается ли это "плохой практикой" задействовать функции C в проектах на С++?
Обычно файл IO-кода должен быть инкапсулирован в реализацию класса или функции. Я бы не считал, что любые варианты, которые вы делаете в инкапсулированных реализациях, являются "плохой практикой", я резервирую этот термин для того, что влияет на пользователя вашей библиотеки или кода (т.е. Интерфейса). Если вы подвергаете свой файловый механизм ввода-вывода в интерфейсе, то IMO, это плохо, если вы используете IO-поток или функции ввода-вывода C-стиля.
Я бы сказал, что функции IO C-стиля (вероятно, всегда) - худший выбор.
В чем преимущества использования потоков по доступу IO C-стиля?
Во-первых, они лучше интегрируются со стандартными конструкциями С++, такими как std::string
. Они довольно хорошо интегрируются с STL <algorithms>
. И они позволяют создавать инкапсулированные пользовательские операторы чтения/записи (< < и → ), так что ваши пользовательские классы почти выглядят как примитивные типы, когда дело доходит до операций ввода-вывода.
Наконец, потоки ввода-вывода на С++ могут использовать механизм исключения для сообщения об ошибках в потоке или операции чтения/записи. Они делают код IO файла намного приятнее, избегая ужасного вида механизмов кода ошибки (последовательность if-операторов и уродливых while-loops, которые проверяют код ошибки после каждой операции).
Ответ 9
Как правило, вы должны предпочесть операторы С++, они:
- безопасный тип. Вы не рискуете пройти двойной, где формат вызывает int.
- Расширяемость. Вы можете написать свои собственные вставки и экстракторы и использовать их.
- Расширяемость. Вы можете определить свои собственные манипуляторы (с помощью конкретный логический смысл приложения) и использовать их. если ты хотите изменить формат всего WidgitNumber (внутренне, int) в вашем выходе, вы меняете манипулятор; вам не нужно искать весь формат где% d - WidgitNumber.
- Расширяемость. Вы можете написать свои собственные раковины и источники, и они могут пересылаться другим стокам и источникам, фильтровать или расширяя вход или выход по желанию.
(FWIW: Я не думаю, что когда-либо писал приложение, которое
не использовал пользовательские → и < операторы, пользовательские манипуляторы и
пользовательский streambuf.)
Ответ 10
Считается ли "плохой практикой" задействовать функции C в проектах на С++?
Нет. Функции C часто используются в проектах на С++. Что касается потоков, Руководство по стилю Google С++, например, рекомендуется использовать их только в ограниченных случаях, таких как "ad-hoc, local, human- читаемые и ориентированные на других разработчиков, а не на конечных пользователей".
Каковы преимущества использования потоков по доступу IO C-стиля?
Основными преимуществами являются безопасность и расширяемость типов. Однако потоки С++ имеют серьезные недостатки, см. ответы на этот вопрос, такие как проблемы с локализацией, плохой отчетностью об ошибках, раздувание кода и проблемы с производительностью в некоторых реализациях.