Блог пользователя freopen

Автор freopen, 16 лет назад, По-русски
Мне захотелось наконец разобраться в способах ввода-вывода в C++, какой из них быстрее и удобнее. Поэтому я написал прогу, которая проверит скорость работы основных способов ввода/вывода в C++.
Итак, разберем все тесты по порядку:

Вывод программы

Test: (printf, 10000000 ints) 2.50c
Test: (cout, 10000000 ints) 3.02c
Test: (write, 10000000 ints, 104827485 chars) 2.88c + 0.25c
Test: (scanf, 10000000 ints) 2.61c
Test: (fwrite, 10000000 ints, 104827485 chars) 2.88c + 0.26c
Test: (cin, 10000000 ints) 8.32c
Test: (printf, 100000000 chars) 1.87c
Test: (scanf, 100000000 chars) 8.44c
Test: (cout, 100000000 chars) 6.98c
Test: (cin, 100000000 chars) 12.51c
Test: (putchar, 100000000 chars) 2.26c
Test: (getchar, 100000000 chars) 1.99c
Test: (read, 100000000 chars) 0.08c + 0.57c
Test: (fread, 100000000 chars) 0.08c + 0.59c

Разбор тестов

  1. printf вывел 107 целых чисел. Относительно быстро и удобно. Вполне можно использовать.
  2. Тоже самое сделал cout. Немного медленнее, но это когда как. Иногда cout работает довольно медленно.
  3. write, как функция ostream. Работает быстро. Очень быстро. Похоже, что в основе лежит fwrite. Первое время - преобразование чисел в строку. Второе - вывод. Примечательно, что вывод куда быстрее.
  4. scanf. Работает ровно также как и printf. Сносно и удобно в использовании.
  5. fwrite. Функция из C. Работает идентично write и сравнимо с ней по сложности использования. Ну может чуть чуть сложнее.
  6. Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.
  7. Переходим к символам. printf выводит символы чуть быстрее, чем числа. Видимо, из-за отсутствия необходимости преобразовывать число.
  8. А вот это стало неожиданностью. scanf на редкость медленно читает символы. Файлик был размером около 100Мб, но все равно мог бы и побыстрее.
  9. cout выводит символы медленно. В 3 раза медленнее, чем printf.
  10. cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб. Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;
  11. putchar. Предназначен для вывода одного символа. И это у него выходит прекрасно. 
  12. getchar. Предназначен для ввода одного символа. И также он это делает очень быстро.
  13. Наконец, блочный ввод-вывод. Опять указано два параметра. Первый - время считывания. Второй - проверка на правильность считывания. Второй нужен только для сравнения. Данные предсказуемо совпадают.
  14. См. выше

Вывод

  1. Для чисел лучше использовать cin(если время не очень критично), или printf(если критично).
  2. Для символов лучше использовать getchar и putchar.
  3. Что-то мне не верится в возможность считать 100Мб данных в оперативку за 0.08 секунд. Есть версия, что файл был кеширован в оперативке. Кто знает, как это проверить и как исправить - пишите в комменты.
  4. Надо доделать тесты для строк и дробного типа. Но это уже попозже.

Тем, кто хочет проверить это на своем компьютере

Пожалуйста. Вот программа: http://pastebin.com/DpmjHF7C. Учтите, что она заменит файл temp.txt на свой, а также ей надо 100Мб свободного места и 200Мб оперативки. И пришлите мне вывод программы в комменты или в личку. Под влиянием этих данных, я возможно, изменю разбор тестов. Большое спасибо всем, кто запустит прогу у себя и пришлет мне результаты, а также тем, кто укажет мне на неточности в программе или предложит другие тесты.
  • Проголосовать: нравится
  • +20
  • Проголосовать: не нравится

16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Почти что с самого начала работы на плюсах использую scanf/printf. Удобно во многих случаях, быстро. cin/cout использую только в случае ввода/вывода string. Ну и getline иногда.
К слову, на экзамене по плюсам теория была на cin/cout, которую я успешно провалил и чуть не получил 4 =)
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
А fputs и fgets (и их аналоги для stdin/stdout puts и gets)? Они после fread и fwrite по скорости будут (быстрее считать строку gets'ом, чем getchar'ами).
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
У меня вопрос: при использовании cin символы читаются до левого пустого символа. Как узнать, какой символ был левым пустым?
  • 16 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +1 Проголосовать: не нравится
    Попробую перефразировать. cin при чтении символа пропускает все whitespace символы. Как узнать, что пропустил cin?
    Если я правильно понял вопрос, то во-первых, обычно не используют cin для такого рода задач. А во-вторых - cin >> noskipws >> c; не будет пропускать whitespace символы.
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
1)
Меня вот это удивило:
Test: (printf, 100000000 chars) 1.87c
Test: (putchar, 100000000 chars) 2.26c
Почему же, интересно, printf обошел putchar...

2)
Быстрее (не медленнее) scanfа и printfа числа читает и пишет вот эта жесть:
int get_num()
{
char c;
int res=0;
do
{
c = getchar();
}
while ( c < '0' || c > '9' );
do
{
res=res*10+c-'0';
c = getchar();
}
while ( c >= '0' && c <= '9' );
return res;
}
void pr_num2( int n )
{
if ( n )
{
pr_num2( n / 10 );
putchar( n % 10 + '0' );
}
}
void pr_num( int n )
{
if ( n )
{
pr_num2( n / 10 );
putchar( n % 10 + '0' );
}
else
putchar('0');
}

Использовал её когда сдавал "на скорость" 1100 на тимусе. :)
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Люди, пост родился из этого комментария. Можете ему написать, что этот пост существует. А то я 5 раз попробовал и не вышло. Спасибо.
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
а где temp.txt взять?
16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
вот характеристики моего ноута:

а вот чё вывело:

  • 16 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Думается мне, что у винды проблемы с непечатаемыми символами. Сейчас поправим код. Ага, вот новый.
    • 16 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится

      o.O

      • 16 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится
        Обратите внимание, насколько putchar(11 строка) шустрее printf(7). Также обратите внимание, что cin(6) в 11 раз медленнее scanf(4). И вообще cin(6,10) тут очень тормоз, а результаты ни капли не смахивают на мои. Однако выводы по использованию остаются те же. У кого есть дополнительная информация по поводу этих (весьма странных) данных - прошу поделиться, ибо я в замешательстве.
16 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится
Если возможно, может ли администрация показать соответствующие циферки на серверах codeforces, чтобы можно было понять, с какой скоростью осуществляется считывание и запись данных?
16 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится
хотелось бы задать пару вопросов, хотя возможно не в подходящий пост...
1) как в С++ перевести коретку на следующую строку? в пасцале это можно сделать readln(), а вот в С++ не знаю(((
2) как в С++ прочитать строку интов? в пасцале это можно записать так : while not eoln do read();

за ранее благодарю!

  • 16 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    1) cout << '\n'; или можно cout << std::endl;
    2) while (cin >> x) {}
    • 16 лет назад, скрыть # ^ |
       
      Проголосовать: нравится -6 Проголосовать: не нравится
      ты с паскалем или делфой знаком немного хоть???
      1) вообще бред, в С++ cin эквивалентен паскалевскому read().
      я же прошу, вот тебе даже такой пример, у тебя на входе дана симметрическая матрица
      1 2 0
      2 3 7
      0 7 9
      а я прошу как считать только :
      1
      2 3
      0 7 9
      т.к. все символы мне нет смысла читать, если сказано что матрица симметрическая.

      2) ты написал пока не конец файла!!! в паскале это эквивалентно while not eof !!!!
      а я прошу пока не конец строки (((

      ЗЫ так в принципе и ожидал что мне это ответят(((
      • 16 лет назад, скрыть # ^ |
         
        Проголосовать: нравится +1 Проголосовать: не нравится
        сорри, невнимательно прочитал твой пост.. И думаю не стоит сразу так резко на это реагировать.
      • 16 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится
        вообще, тебе это скорее всего надо для того, чтобы писать лабы по ВМА с симметрическими матрицами.. но там они и будут введены как треугольные. В противном случае в С++ ничего такого нету, считывай строку - из неё выдирай инты.
  • 16 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Не знаю, как надо "правильно", но я в таких случаях делаю так:
    1) scanf("\n");

    2)     string str;
    getline(cin, str);
    stringstream ss(str);
    int elem;
    while (ss >> elem) {
    DoSmthWith(elem);
    }
    • 16 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится
      а нельзя ли читать инты не выделяя их из строки? просто в таком случае будет быстрее читать посимвольно и выделять инты. или я не прав?
      • 16 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится
        Считать строку быстрее, потом из неё sscanf'ом считывать всё что хочешь в любом формате. Перевести каретку можно, например, с помощью gets, но в любом случае надо дочитать строку до конца(и в паскале тоже), чтобы узнать где её конец:) Так что от считывания всего ввода не убежишь.
    • 16 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится
      1) Так не стоит делать. Смотри мой ответ снизу.
  • 16 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    1)
    char buffer[100500];
    gets(buffer);

    НЕ РЕКОМЕНДУЕТСЯ писать scanf("\n"); так как он прочитает все пробельные символы (т.е. может сразу несколько пустых строчек зохавать).

    2)

    while ( scanf("%d", &n) == 1 ) {
        ...
    }

    Сканф возвращает количество удачно прочитанных аргументов.
    Если он не может прочитать то, что его просят (если там один аргумент), то он возвращает 0.
    Если и прочитать ничего не удалось, и настал конец файла – сканф будет выдавать -1.

    ПОЭТОМУ не стоит писать так:
    while ( scanf("%d", &n) )

    Много раз сам валился на этом. :)
    • 16 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится
      1) Спасибо, не знал. В олимпиадных задачах чаще всего нужно просто пропустить все пробелы и переводы строк до нужных данных. Там scanf("\n") работает.

      2) while ( scanf("%d", &n) == 1 ) { ... } 
      читает все числа из файла, а тут нужно одну строчку. Лучше всего тут прочитать сначала строку, а потом распарсить sscanf-ом или stringstream-ом. 

      • 16 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится
        1) Я раньше тоже всегда так читал. :)
        А потом в Сазанке у нас упала программа вот с таким тестом.
        3
                       
        a b c
        d e f

        scanf("\n") прочитал аж до начала третей строчки. Потом три gets() в цикле выдали 3ю, 4ю и 4ю (!) строчки у нас был стабильно WA.

        2) Вот теперь я неправильно прочитал))
        Привожу рабочий код sscanf (спасибо Foton за по сути его написание :)

        char buffer[10000], *iter, s[1000];

        int main()

        {

            gets(buffer);

            iter = buffer;

            while ( *iter == ' ' )

                    iter++;

            while ( sscanf(iter, "%s", &s) == 1 )

            {

                sscanf(s, "%d", &a);

                printf("%d ", a);

                iter += strlen(s);

                    while ( *iter == ' ' )

                        iter++;

            }

            return 0;

        }

16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

вот:

16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Test: (printf, 10000000 ints) 11.34c

Test: (cout, 10000000 ints) 27.69c

Test: (write, 10000000 ints, 56609008 chars) 6.67c + 1.55c

Test: (scanf, 10000000 ints) 7.17c

Test: (fwrite, 10000000 ints, 56609008 chars) 6.67c + 1.31c

Test: (cin, 10000000 ints) 31.34c

Test: (printf, 100000000 chars) 41.64c

Test: (scanf, 100000000 chars) 52.09c

Test: (cout, 100000000 chars) 25.36c

Test: (cin, 100000000 chars) 69.89c

Test: (putchar, 100000000 chars) 14.25c

Test: (getchar, 100000000 chars) 18.23c

Test: (read, 100000000 chars) 1.55c + 0.53c

Test: (fread, 100000000 chars) 1.17c + 0.47c

16 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Проект, на котором тестируется скорость различных языков на различных системах: http://shootout.alioth.debian.org/
15 лет назад, скрыть # |
 
Проголосовать: нравится +3 Проголосовать: не нравится
советаю функцию scanf("%d", &var) писать так:

var = get();

inline int get()
{
    for (C = getchar(); (C < 48 || C > 57) && C != '-'; C = getchar());
    if (C == '-')
        neg = 1,
        C = getchar();
    else
        neg = 0;
    x = 0;
    for (; 47 < C && C < 58; C = getchar())
        x = x*10 + C - 48;
    if (neg)
        return -x;
    else
        return x;
}


Функция get() читает по одному символу и преобразовывает эти символы в число.

Тэстил. Заметно ускоряет время.
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Почитай вот эту ветку. У меня было что-то подобное.
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +3 Проголосовать: не нравится

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

    • 15 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится
      Авторы олимпиадных задач все-таки разные бывают и расслабляться не стоит в любом случае. А такие трюки иногда помогают протолкнуть n^2 при n=10000, если нужен nlogn. Редко, правда. Но вот на codeforces люди начинают выть даже если задачи незначительно отличаются от среднестатистической задачи. И потом, кто сказал, что знание тонкостей языка бесполезно. Оно может помочь в задачах на оптимизацию, в которых не надо особо оптимизировать ввод.
15 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится 0 Проголосовать: не нравится
А вот эту штуку не пробовал? http://mirror.codeforces.com/blog/entry/10
Хорошо бы и с ней протестить cin, cout . . .
15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Вопрос по С++ или даже по Visual Studio, но относится к ТопКодеру.

Писал долго SRMы в NetBeans на Java и был доволен, но сегодня меня Java по некоторым причинам разочаровала и не в первый раз, так что я решил вернуться к С++.

Теперь вопрос: как сделать, чтобы в режиме отладки окно консоли не закрывалось мгновенно? Я использую плагин moj, но не знаю, как его модифицировать, чтоб вписать туда что-то типа system("pause");

Второй вопрос. Где нужно поставить галочку в настройках, если это вообще возможно, чтобы закрывающиеся скобки (и обычные, и фигурные) добавлялись автоматически? Особо хочется добавления фигурных скобок - в NetBeans привык и теперь совсем непривычно их самому ставить.

Третий вопрос. Какой самый правильный способ перевода строки в число и обратно и чтения чисел из строки?
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Ну есть stringstream, он действует и туда и обратно, правда он тормознутый зараза... Перевод из строки в число если в 32-битный то atol(atoi), 64-битный я ручками перевожу если stringstream в ТЛ хочет уйти.
    Действует stringstream так:
    #include<sstream>
    ...
    int n; string s;
    cin >>s;
    stringstream ss;
    ss <<s;
    ss>>n;
    ну и в обратную точно так же:
    ss<<n;
    ss>>s;
  • 15 лет назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится 0 Проголосовать: не нравится

    1) Чтение чисел из строки без тормозов:

    char str[mxx]="1 2";

    sscanf(str,"%d %d",&n,&m);

    2) Строка в число для 64-битных чисел без тормозов:

    char str[mxx]="12345678910111213";

    long long big;

    sscanf(str,"%I64d",&big);

    Про консоль не очень понял. Если в режиме отладки, то ставишь breakpoint на последний return 0. А если просто запустить и посмотреть что вывелось на консоль, то как вариант написать _getch() //#include <conio.h> . Не забыть его потом убрать!!! :)

    • 15 лет назад, скрыть # ^ |
      Rev. 2  
      Проголосовать: нравится 0 Проголосовать: не нравится
      Проблема была с консолью в том, чтобы мне этот getch() или system("pause") не писать вручную каждый раз. Кажется, разобрался, как поместить это в плагин.

      Ладно, и sscanf как-нибудь попробую.
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Чтение чисел... Ну можно int n;cin>>n, scanf("%d",&n) и его разновидности. Лучше все-таки сканф, т.к. можно чтобы кое-какие символы пропускал-ставишь эти символы после %d
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    как сделать, чтобы в режиме отладки окно консоли не закрывалось мгновенно? Я использую плагин moj, но не знаю, как его модифицировать, чтоб вписать туда что-то типа system("pause");

    Ctrl + F5?
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    1) Используй "Win32 Console Application" вместо "Empty Project" при создании проекта. Поставь галку в "Additional options->Empty project" чтобы созданный консольный проект был чистым. 
15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
спасибо за статью. помогла уложить в ограничения.
15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Какой rand() на твоей машине? В Windows и Linux они отличаются!
15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Для создания временного файла лучше использовать tmpfile (http://cplusplus.com/reference/clibrary/cstdio/tmpfile/) или tmpnam (http://cplusplus.com/reference/clibrary/cstdio/tmpnam/). Также можно временный файл удалить в конце или через atexit.
15 лет назад, скрыть # |
Rev. 3  
Проголосовать: нравится 0 Проголосовать: не нравится
> Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.

> cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб.

Это потому что вы неправильно используете потоки для считывания... Попробуйте так:

void test_ifstream_int() {
	int cur = clock();
	ifstream ifs("temp.txt", ifstream::in);
	for(int i = 0; i < N; i++) {
		int t;
		ifs >> t;
		if(t != a[i]) {
			fprintf(stderr, "Fail with ifstream\n");
			exit(1);
		}
	}
	ifs.close();
	fprintf(stderr, "Test: (ifstream, %d ints) %.2lfc\n", N, (clock() - cur + .0) / CLOCKS_PER_SEC);
}

ну и, соответственно так:
void test_ifstream_char() {
	int cur = clock();
	ifstream ifs("temp.txt", ifstream::in);
	for(int i = 0; i < N; i++) {
		char t;
		ifs >> t;
		if(t != s[i]) {
			fprintf(stderr, "Fail with ifstream\n");
			exit(1);
		}
	}
	ifs.close();
	fprintf(stderr, "Test: (ifstream, %d chars) %.2lfc\n", NC, (clock() - cur + .0) / CLOCKS_PER_SEC);
}

Результат:
Test: (cin, 10000000 ints) 6.04c
Test: (ifstream, 10000000 ints) 2.08c
Test: (cin, 100000000 chars) 9.43c
Test: (ifstream, 100000000 chars) 0.19c

Просто использовать небуферизированный ввод для чтения 100МБ - это как-то не по-программистски. ;)



> Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;

Может лечится гораздо проще... cin.get(t); вместо cin >> t; - заодно и производительность вырастает.
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Гораздо проще - понятие растяжимое. К примеру, у меня в программе символ считывается в 30-40 местах, тогда уж лучше noskipws, чем везде переделывать.
15 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится
А как в timus 1000 задачу за 0.001 сдают ? Особый ввод вывод ?
15 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится
После добавления в начало main() шаманства для ускорения потоков -- "std::ios_base::sync_with_stdio(false);", программа начала падать:
===
Test: (printf, 10000000 ints) 2.45c
Test: (cout, 10000000 ints) 3.08c
Test: (write, 10000000 ints, 104827485 chars) 3.13c + 0.31c
Fail with scanf
===
Строка компиляции: g++ -Wall q.cpp -o q
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Никто не в курсе почему такое происходит и как с этим бороться?
Если закомментить падающие методы, то, как и ожидалось, потоки показывают примерно такую же производительность, что и scanf/printf.
15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
Много и трудно мне пришлось бороться за производительность C/C++ ных программ на разных платформах, начиная от тех у которых аж по 1кб оперативки... И я одно скажу - обязательно нужно указывать компилятор, указывать опции оптимизации с которыми выполнялась проверка... Ну и всё равно интерес в этом сравнении останется довольно академическим... ;-)
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Академическим, как и многое на этом сайте.
  • 14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится -6 Проголосовать: не нравится

    У меня есть практическая статья на эту тему, правда больше для новичков и про текстовые файлы. Советы и приёмы использования C++ I/O

    • 14 лет назад, скрыть # ^ |
      Rev. 2  
      Проголосовать: нравится +10 Проголосовать: не нравится

      Раз уж поднялась эта древняя тема.. По советам по ссылке выше

      Вот такая вот конструкция while (!std::getline(inf, name, '|').eof()) обычно не используется. Короче, да и корректнее while (std::getline(inf, name, '|'))

      • 14 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится

        И чем же это корректней?

        • 14 лет назад, скрыть # ^ |
           
          Проголосовать: нравится +9 Проголосовать: не нравится

          Тем, что читает, пока может прочитать, а не пока не конец файла.

          • 14 лет назад, скрыть # ^ |
             
            Проголосовать: нравится -7 Проголосовать: не нравится

            getline() возращает поток, а не bool. То что C++ даёт возможность приводить всё что угодно к bool радует, в основном, любителей писать "магический код", вроде такого

            if (w) { // CHip and DAle }

            Заставляющий читающего вспоминать все слова что он знает на 'w', такие что могут быть true/false, вместо того что написать нормально

            if (thread_worker != NULL) { // banana banana }

            Что еще хуже, ваша замена меняет смысл. Проверяя eof() автор соглашается выйти из цикла только в случае eof(). Если произойдет другая ошибка, её можно обработать в теле цикла, и продолжить чтение, т.к. ошибка может быть в конкретных данных (а не во всех) или во временных обстоятельствах.

            • 14 лет назад, скрыть # ^ |
               
              Проголосовать: нравится +20 Проголосовать: не нравится
              1. Есть вещи, которые становятся в языке идиомами, и их использование для профессиональных программистов не выглядит чем-то магическим.

              2. В приведенном по ссылке коде в теле цикла нет никаких проверок. Поэтому, если произойдет другая ошибка, то он останется в цикле навсегда.

              http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.5

              • 14 лет назад, скрыть # ^ |
                 
                Проголосовать: нравится +8 Проголосовать: не нравится

                Частично соглашусь с Petrosian.

                В идеале мои собственные функции работы с потоками возвращали бы количество считанных байт/символов. Если это неприменимо (например, для чисел), пусть результатом будет bool успешности считывания.

                Почему приходится вызывать 2 функции вместо одной (например, gcount после getline) для меня не очень понятно.

                Но приходится работать с тем, что есть. И eof действительно недостаточно надёжная функция.

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Test: (printf, 10000000 ints) 2.15c Test: (cout, 10000000 ints) 2.36c Test: (write, 10000000 ints, 104827485 chars) 3.14c + 0.30c Test: (scanf, 10000000 ints) 3.22c Test: (fwrite, 10000000 ints, 104827485 chars) 3.14c + 0.41c Test: (cin, 10000000 ints) 8.65c Test: (printf, 100000000 chars) 2.04c Test: (scanf, 100000000 chars) 7.30c Test: (cout, 100000000 chars) 6.61c Test: (cin, 100000000 chars) 9.88c Test: (putchar, 100000000 chars) 2.10c Test: (getchar, 100000000 chars) 1.66c Test: (read, 100000000 chars) 0.04c + 0.79c Test: (fread, 100000000 chars) 0.04c + 0.79c

»
13 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Hi, I found that by adding ios_base::sync_with_stdio(false); cin.tie( static_cast<ostream*>(0) );

cin performance boosts drastically. However, it makes it work wrong when used along stdio.

»
13 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Если не ошибаюсь, можно сделать такую штуку: cin.sync_with_stdio(false); cout.sync_with_stdio(false); Тогда cin и cout будут работать гараздо быстрее.

  • »
    »
    13 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Да ладно?

  • »
    »
    13 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Можно заменить на одну строчку

    ios_base::sync_with_stdio(0);
    
  • »
    »
    13 лет назад, скрыть # ^ |
    Rev. 3  
    Проголосовать: нравится +17 Проголосовать: не нравится

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

    Тогда бы вы, например, узнали, что ваши 2 строчки делают одно и тоже 2 раза. Что эквивалентно тому что сделать 1 раз. Собственно, вызывают статический метод, объект которому не нужен