Ale to z racji tego, że jest to bug GCC ;> |
To nie jest bug. Jeśli coś tu miałoby być bugiem, to prędzej fakt, że
std::cin.sync()
gdziekolwiek działa. Ze standardu dość jasno wynika, że zamierzenie
sync jest zupełnie inne i ta funkcja służy do opróżnienia bufora
wyjściowego (więc powinna się nazywać
flush) (27.6.3.4.2/7):
Effects: Synchronizes the controlled sequences with the arrays. That is, if pbase() is non-null the characters between pbase() and pptr() are written to the controlled sequence. The pointers may then be reset as appropriate. |
std::cin.sync()
pod Windowsem zachowuje się, jakby robiło to, o co programiście chodzi przez czysty przypadek: dla libstdc++
std::cin.rdbuf()
to zwykle
__gnu_cxx::stdio_sync_filebuf, którego
sync to
return std::fflush( _M_file );
… ale już po wyłączeniu synchronizacji z stdio
cin dostaje zupełnie inny
streambuf, gdzie
sync nie wywołuje
std::fflush i
std::cin.sync()
przestaje "działać"*. Nawet, jeśli synchronizacja jest włączona, wystarczy, że standardowe wejście jest potokiem, żeby "synchronizacja" przestała cokolwiek synchronizować.
W bibliotece standardowej Dinkumware/Microsoftu
sync_with_stdio nie robi nic użytecznego, synchronizacja z stdio włączona jest cały czas… i podobnie jak w przypadku libstdc++, wystarczy potok zamiast terminala, żeby wszystko się rozleciało.
W libc++
std::__1::__stdinbuf nie ma
żadnej implementacji
sync. To oznacza użycie domyślnej z
std::basic_streambuf, która zgodnie ze standardem po prostu zwraca zero.
Fakt, że to gdziekolwiek zachowuje się, jakby działało jest skutkiem tego, że
msvcr* (najprawdopodobniej jako
jedyna licząca się implementacja biblioteki standardowej C) definiuje
fflush na strumieniu wejściowym. Według standardu jest to niezdefiniowane, nawet
sam Microsoft przyznaje, że to rozszerzenie.
Jaki w ogóle jest cel wywoływania
std::cin.sync()
? Żeby wyczyścić bufor klawiatury? No dobra, tylko tej klawiatury może tam nie być (np. potok) albo strumień może nie mieć pojęcia, że tam jest klawiatura (np. libstdc++ z wyłączoną synchronizacją z stdio). W ogóle, po co czyścić bufor klawiatury? Po to, by pominąć wszystkie znaki, które użytkownik w tej linii wprowadził? To dlaczego nie napisać tego wprost?
std::cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
może i jest przydługie, ale działa praktycznie zawsze i wszędzie.
* przykład:
>> cat x.cpp
#include <iostream>
int main()
{
std::ios::sync_with_stdio(false);
int a;
int b;
std::cin >> a;
std::cin.clear();
std::cin.sync();
std::cin >> b;
std::cout << (std::cin.good() ? "ok" : "!!!not!!!");
}
>> g++ x.cpp; ./a
xxx
!!!not!!!