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

Автор Totktonada, 10 лет назад, По-русски

Собственно заголовок говорит сам за себя =) В очередной раз получил ТЛ из-за сина. Что в этом случае делает нормальный человек? Переходит наконец на сканф/принтф. Что делаю я? Пишу какую-то ересь, которая подменяет одно другим.

#ifdef WIN32
#define LLD "%I64d"
#else
#define LLD "%l" "ld"
#endif
#define cin mycin
#define cout mycout
#define endl '\n'
struct io {
io operator» (int& x) {scanf("%d",&x); return *this; }
io operator» (LL& x) {scanf(LLD,&x); return *this; }
io operator» (double& x) {scanf("%lf",&x); return *this; }
io operator» (char& x) {scanf("%c",&x); return *this; }
io operator» (char* x) {scanf("%s",x); return *this; }
io operator» (string& x) {scanf("%s",x.c_str()); return *this; }
io operator« (int x) {printf("%d",x); return *this; }
io operator« (LL x) {printf(LLD,x); return *this; }
io operator« (double x) {printf("%.8lf",x); return *this; }
io operator« (char x) {printf("%c",x); return *this; }
io operator« (char* x) {printf("%s",x); return *this; }
io operator« (string x) {printf("%s",x.c_str()); return *this; }
};
io cin, cout;

Вряд ли этот адовый ад стоит использовать в жизни. Но чисто теоретически интересно: будет ли это работать достаточно быстро? Или такая структура существенно утяжеляет "голые" сканф/принтф? И, возможно, стоит как-то пошаманить с typeof и сделать несколько кейсов внутри одной перегрузки, чем писать 100500 их? В общем, интересно, насколько оптимальным это может быть.

  • Проголосовать: нравится
  • +17
  • Проголосовать: не нравится

»
10 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится
        std::ios_base::sync_with_stdio(0);
        std::cin.tie(0);

7647752

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

    Спасибо, уже знаю =) Просто вот тут (если я правильно понимаю статистику-результат) говорится о том, что под студией cin/cout даже с этими оптимизациями работает медленнее. Мне интересно, насколько плох именно этот изврат.

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

По идее, вызов функции — операция в десятки раз более дешевая, нежели непосредственно ввод-вывод.

Тем более, функции-члены у Вас тут невиртуальные, вызов таких функций отличается от вызова обычных только необходимостью передавать в качестве еще одного параметра указатель на объект.

Но, ИМХО, писать такой код — извращение. Даже в олимпиадном контексте. Тем более, что выше уже привели более простой вариант (правда, работающий только под GCC).

»
10 лет назад, # |
Rev. 3   Проголосовать: нравится +6 Проголосовать: не нравится

Возвращать надо io&. И в io::operator<< передавать string const&.

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

Вряд ли этот адовый ад стоит использовать в жизни. Но чисто теоретически интересно: будет ли это работать достаточно быстро? Или такая структура существенно утяжеляет "голые" сканф/принтф? И, возможно, стоит как-то пошаманить с typeof и сделать несколько кейсов внутри одной перегрузки, чем писать 100500 их? В общем, интересно, насколько оптимальным это может быть.

Нисколько не утяжелит. Лишний вызов функции — чепуха, по сравнению с тем, что происходит внутри сканфа. К тому же можно заинлайнить.

Перегрузка никоим образом не влияет на время выполнения, так как то, какая функция будет вызываться, известно уже на стадии компиляции.

»
10 лет назад, # |
  Проголосовать: нравится +22 Проголосовать: не нравится

Функция считывания стрингов написана неправильно. Код же даже не компилируется: c_str() это const char*, его содержимое менять нельзя.

Стандартом 2003 года языка C++ не регламентируется, что basic_string<T> должен быть реализован как сплошной массив символов. Условно говоря, стринг может быть двусвязным списком символов. Поэтому c_str() вполне может быть реализован как "копируем содержимое строки в некоторый буфер и возвращаем этот новосозданный буфер". Стало быть, считывание в него, не приведёт к изменению самой строки. Впрочем, вроде, ни один разумный компилятор так не делает. А вот в стандарте 2011 года в пункте 21.4.1.5 уже регламентировано, что строка реализуется как сплошной массив символов поэтому можно писать scanf("%s", &(*x.begin())).

С другой стороны, у этого подхода есть проблема, заключающаяся в том, что приходится аккуратно контролировать вместимость строки: считывание может запросто переполнить зарезервированный буфер. Также после считывания x.size() не будет иметь никакого отношения к реальной хранимой строки, scanf плюхнет где-то внутри нулевой символ, и это никак не отразится на том, что про длину строки думает структура.

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

    Странно, у меня спокойно компилируется (VS C++ 2005 Express). А со стрингами действительно лажа, спасибо, сначала не заметил, хотя проверял вроде.

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

      Действительно, это дело компилируется, но с warning'ом, а у меня стоит опция treat warnings as errors. В общем, не стоит так делать.