16 Haziran 2020 Salı

Streamler std::istream Sınıfı - std::cin

std::cin Nedir
Açıklaması şöyle.
std::cout and std::cin are global objects of classes std::ostream and std::istream respectively, which they've overloaded operator << and >>.
Dolayısıyla std::istream sınıfının tüm metodlarını kullanmak mümkün.

Constructor - streambuf
istream parametre olarak verilen streambuf nesnesini sahiplenmez. Dolayısıyla streambuf nesnesi heap'te yaratılmış ise silmez. Bu durumda şöyle yaparız.
class config_istream : public std::istream {
public:
  config_istream(std::string name) : 
    std::istream(fslib.InputStream(name.c_str())) 
  {
  }

  ~config_istream() { delete rdbuf(); }
};
Örnek
Bu sınıf en çok bir bellek alanından bir şey okumak için kullanılır. Şöyle yaparız.
#include <iostream>
#include <istream>
#include <streambuf>
#include <string>

struct membuf : std::streambuf
{
  membuf(char* begin, char* end) {
    this->setg(begin, begin, end);
  }
};

int main()
{
  char buffer[] = "I'm a buffer with embedded nulls\0and line\n feeds";

  membuf sbuf(buffer, buffer + sizeof(buffer));
  std::istream in(&sbuf);
  std::string line;
  while (std::getline(in, line)) {
    std::cout << "line: " << line << "\n";
  }
  return 0;
}
Aynı iş için  istringstream'i kullanmak çok daha kolay.
std::string a = "abc..";
std::istringstream istr (a);
Örnek
Eğer streambuf olarak null vermek istersek şöyle yaparız.
std::istream in(0);
copy - constructor
Bu sınıfı kopyalamak mümkün değil. Açıklaması şöyle
An istream object, for example, represents a stream of input values, some of which may have already been read, and some of which will potentially be read later. If an istream were to be copied, would that entail copying all the values that had already been read as well as all the values that would be read in the future? The easiest way to deal with such questions is to define them out of existence. Prohibiting the copying of streams does just that
bad metodu
Şöyle yaparız.
std::istream is = ...
std::cout << "is.bad(): " << is.bad();
clear metodu
Tüm bitleri temizler.

goodbit : Diğer bitlerin atanmadığını, herşeyin yolunda olduğunu döner.
eofbit : End of File, yani dosya sonunun aşıldığını belirtir.
failbit : I/O işleminde hata olduğunu belirtir. Genellikle formatlama hatasıdır.
badbit : Geri dönülemez bir hata olduğunu belirtir. Stream'in dosya başından da önceye kaydırılması örnek verilebilir.

Bitleri yazdırmak için şöyle yaparız. Ancak bu bitler gerçekte bit olarak temsil edilmeyebilir. Dolayısıyla eof(), fail(), bad() metodlarını kullanmak daha iyi.
istream is = ...;
cout << is.eofbit << " " << is.failbit << " " << is.badbit << endl;
Şimdi bitlerin nasıl kullanıldığına bakalım

good biti
Şu açıklama bu bitin ne işe yaradığını anlatıyor.
good() returns 0 if it has a problem reading from the file, file not existing, etc
failbit biti
Eğer okuma işlemi başarısız olursa failbit kaldırılır. Aynı zamanda okuma işlemi de false döner. Stream'in Boolean bir değer dönmesinin sebebi aşağıda belirtilen Boolean metodlarıdır.
do {
    std::cout << "Enter the employee ID: ";
} while(!(std::cin >> e.id));
failbit şöyle kontrol edilir ve temizlenir.
if (!std::cin) {
  std::cin.clear();
  ...
}
Sadece belli bir biti temizlemek istersek şöyle yaparız.
std::cin.clear(std::cin.rdstate() & ~std::ios::failbit);
eof metodu
std::cin içn Ctrl + Z ile eof gönderilir. Açıklaması şöyle.
The end-of-file character (CTRL-Z on the keyboard) sets the internal state flag of std::cin to eofbit, which must be cleared with basic_ios::clear() before following calls to getline will work properly.
.
Örnek
Şöyle yaparız.
std::istream is = ...
std::cout << "is.eof(): " << is.eof();
fail metodu
Okuma işlemine verilen tip ile veri uyuşmazsa fail() eder. fail etmiş stream'i kurtarmak için genellikle girdi temizlenir. Yani şöyle yapılır.
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Örnek
Şöyle yaparız.
std::istream is = ...
std::cout << "is.fail(): " << is.fail();
Örnek
Şöyle yaparız.
int letter = 0;

while (1) {
  std::cout << "Please type in a number: ";
  std::cin >> letter;

  if (std::cin.eof()) {
    std::cout << std::endl;
    return 1;
  } else if (std::cin.fail()) {
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    std::cout <<"Integer input required. Try again.\n";
  } else if (letter < 1 || letter > 26) {
    std::cout <<"The English alphabet only has 26 letters. Try again.\n";
  } else {
    break;
  }
}
gcount metodu
Şöyle yaparız.
std::size_t read_size = is.gcount();
get metodu
Şöyle yaparız.
char c;
cin.get (c);
Döngü içinde kullanmak için şöyle yaparız.
while(std::cin.get(c)) {...}
cin ile binary veri okumak mümkün değil. Örneğin Binary veri içinde Ctrl + Z'ye denk geliyorsa, bunu durma karakteri olarak algılar. Windows'ta cin'i binary mod'a geçirmek için şöyle yaparız.
_setmode(_fileno(stdin), _O_BINARY);
cin.read(...);
getline metodu
Bu metod nedense C tipi char * alıyor. std::string ile direkt çalıştıran bir metodu yok. Aslında buffer'dan bir şey okutmak için çok kullanışlı.

Eğer stream'i kurarken verilen belleği okutmak istersek, std::getline (myistream) şeklinde kullanmak gerekir.

ignore metodu
Belirtilen karakter veya sayıya kadar veriyi es geçerek tüketir.
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Özellikle menü sunan konsol programlarında satır sonuna kadar okuma için kullanılabilir. Beklenen değer okunduktan sonra geriye kalan tüm boşlukları dikkate almaz. Burada ignore() metodunun kullanıldığı görülebilir.
template <typename T>
T easy_input( std::istream& is = std::cin )
{
  T value{};
  is >> value;
  is.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
  return value;
}
Okunan değeri bir predicate ile kontrol etmek için şöyle yaparız.
template <typename T, typename Predicate>
T easy_input( Predicate pred, std::istream& is = std::cin )
{
  T value{};
  while ( !pred( value = easy_input<T>() ) ) //yukarıdaki easy_input'u kullanır
  {}
  return value;
}
Bu metodu şöyle kullanırız.
int value = easy_input<int>( [] ( int i ) { return i >= 0 && i <= 10; } );
operator >> metodu
C++11'e kadar okuma işleminde hata olursa okuma yapılan değişken güncellenmiyordu.
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
C++11'den sonra ile okumada hata olması durumunda, değeri saklayan değişkene 0 yazılmaya başlandı. Örnekte a girdisi verirsek - hatalı bir girdi - x'in değeri 0 olur.
#include <iostream>

int main()
{
  int x = 5;
  std::cin >> x;
  std::cout << x << '\n';
}
Örnek
Elimizde >> operator'ünü sağlamayan bir sınıf olsun. Şöyle yaparız.
SalesItem book;
std::cin >> book ;
Bu durumda şu hatayı alırız.
error: no match for 'operator>>' (operand types are 'std::istream
{aka std::basic_istream<char>}' and 'Sales_item')
Sınıfa operator>> metodunu eklemek için şöyle yaparız.
class SalesItem {
  std::string m_item_name;
  int m_itemno;

public:
  friend std::istream& operator>>(std::istream& o,Sales_item& obj) {
    o>>obj.m_item_name>>obj.m_itemno;
    return o;
  }

  friend std::ostream& operator<<(std::ostream& o,const Sales_item& obj) {
    o<<obj.m_item_name<<' '<<obj.m_itemno;
    return o;
  }

};
operator void* metodu
!fail olup olmadığını döner.

operator !() metodu
 fail olup olmadığını döner.

Bu metodlar sayesinde stream if ve while içinde kullanılabilir.
if (stream >> x)
{    
}

while(stream)
{
    /* do Stuff */
}
peek metodu
Örnek
Şöyle yaparız.
 // Skip all white space
 while (std::isspace(std::cin.peek()))
  std::cin.get();
Örnek
Şöyle yaparız.
std::istream& eat_whitespace(std::istream &is) // eats whitespace except '\n'
{
  int ch;
  while (is && (ch = is.peek()) != EOF && ch != '\n'
            && std::isspace(static_cast<char unsigned>(ch)))
  {
    is.get();
  }
  return is;
}
read metodu
Şöyle yaparız.
std::size_t const buf_size = 256;
char buf[buf_size] = { '\0' };
is.read(buf, buf_size);
rdbuf metodu
Herhangi bir istream akımını unbuffered hale getirmek için şöyle yapılır.
std::ifstream in;
in.rdbuf()->pubsetbuf(0, 0);
in.open("/dev/random");
putback metodu
Okunan karakteri geri koyar. Şöyle yaparız.
std::istream in = ...;
char c, d;
in >> c >> d;
if (c == d) {
  
  in.putback(d);
  in.putback(c);
}
readsome metodu
Açıklaması şöyle. Dolayısıyla read() metodunu kullanmak daha iyi olabilir.
The behavior of this function is highly implementation-specific. For example, when used with std::ifstream, some library implementations fill the underlying filebuf with data as soon as the file is opened (and readsome() on such implementations reads data, potentially, but not necessarily, the entire file), while other implementations only read from file when an actual input operation is requested (and readsome() issued after file opening never extracts any characters). Likewise, a call to std::cin.readsome() may return all pending unprocessed console input, or may always return zero and extract no characters.
Şöyle yaparız.
char c[1024] = {};
std::streamsize num = std::cin.readsome(c, 1023);
rdstate metodu
Şöyle yaparız.
istream &is = ...
cout << is.rdstate() << endl;
setstate metodu
Bir biti elle atamak istersek şöyle yaparız.
in.setstate (std::ios_base::failbit);
sync metodu
Alttaki stream değiştiyse değişiklikleri almak için kullanılır. Şöyle yaparız.
is.sync();
tie metodu - istream Sınıfına Bağlı ostream Nesnesini Döner
Normalde cin ve cout birbirlerine bağlıdırlar. Yani önce cout daha sonra cin işlemi çalışır. Böylece prompt edilen metin ekranda görüldükten sonra cin işleminin çalışacağı garanti edilir. Bu metoda 0 veya NULL geçerek cin ve cout arasındaki bu bağlantı koparılabilir. Açıklaması şöyle
If cin and cout are tied, you can expect the output to be flushed (i.e., visible on the console) before the program prompts input from the user. If you untie the streams, the program might block waiting for the user to enter their name but the "Enter name" message is not yet visible (because cout is buffered by default, output is flushed/displayed on the console only on demand or when the buffer is full).

So if you untie cin from cout, you must make sure to flush cout manually every time you want to display something before expecting input on cin.

In conclusion, know what each of them does, understand the consequences, and then decide if you really want or need the possible side effect of speed improvement.
Her stream tie() sonucunda bir şey döndürmüyor.

Örnek - Bağlantıyı koparmak
Şöyle yaparız. 0 yerine NULL da kullanılabilir.
cin.tie(0);
Şöyle yaparız
cin.tie(NULL);
Örnek
Elimizde şöyle bir kod olsun. Bu metod istream'in bağlı olduğu Prompt stream'ini alır ve bir metin gösterir.
namespace stdex // not std namespace
{

  template <typename Input, typename Prompt>
  Input easy_input(const Prompt& prompt,std::istream& in = std::cin)
  {
    auto user_input_value = Input{}; // initialize value on creation
    auto tied_stream = in.tie();
    if(tied_stream)
      (*tied_stream) << prompt;
    if(!(in >> user_input_value))
      throw std::runtime_error{ "easy_input: Bad input" }; // handle errors
    return user_input_value;
  }
}
Bu metod verilen stream'e göre Prompt etmeli. Aşağıdaki kodda istringstream bir outputstream'e bağlı olmadığı için prompt çalışmaz.
auto a = stdex::easy_input<std::string>("name: ");

std::istringstream in{ "aaa bbb" };
auto b = stdex::easy_input<std::string>(">> ", in); // will not prompt
Şu kodda ise çalışır.
std::istringstream in{ "aaa bbb" };

std::ostringstream out;
in.tie(&out);
auto c = stdex::easy_input<std::string>(">> ", in);
assert(">> " == out.str());
Diğer
C++'taki stream'ler ile C metodları birlikte çalışmazlar. istream'deki veriyi okuyup C'deki FILE yapısına kopyalamak için Linux'ta fopencookie kullanılabilir.

Record Okumak
Elimizde : karakteri ile ayrılmış alanlar olsun. Şöyle yaparız.
struct expect
{ 
  char c; 
  expect( char c ): c(c) { }
};

std::istream& operator >> ( std::istream& ins, const expect& c )
{
  ins >> std::ws;
  if (ins.peek() == c.c)
    ins.get();
  else
    ins.setstate( std::ios::failbit );
  return ins;
}

std::istream& operator >> ( std::istream& ins, Mammal& mammal )
{
  return ins 
    >> mammal.species
    >> mammal.dateOfBirth.month    >> expect( ':' )
    >> mammal.dateOfBirth.day      >> expect( ':' )
    >> mammal.dateOfBirth.year
    >> mammal.weight
    >> mammal.enclosureSize.length >> expect( ':' )
    >> mammal.enclosureSize.width  >> expect( ':' )
    >> mammal.enclosureSize.height
    >> mammal.exhibit;
}
Çağırmak için şöyle yaparız.
std::vector <Mammal> mammals;

int num_mammals;
std::cin >> num_mammals;

Mammal mammal;
while (std::cin >> mammal)
  mammals.push_back( mammal );






Hiç yorum yok:

Yorum Gönder