2014-12-10 13 views
6

Sau đây là an example from cppreference.com,Confused về việc sử dụng 'std :: istreambuf_iterator'

The Code is: 
#include <vector> 
#include <sstream> 
#include <iostream> 
#include <iterator> 

int main() 
{ 
// typical use case: an input stream represented as a pair of iterators 
std::istringstream in("Hello, world"); 
std::vector<char> v((std::istreambuf_iterator<char>(in)), 
         std::istreambuf_iterator<char>()); 
std::cout << "v has " << v.size() << " bytes. "; 
v.push_back('\0'); 
std::cout << "it holds \"" << &v[0] << "\"\n"; 


// demonstration of the single-pass nature 
std::istringstream s("abc"); 
std::istreambuf_iterator<char> i1(s), i2(s); 
std::cout << "i1 returns " << *i1 << '\n' 
      << "i2 returns " << *i2 << '\n'; 
++i1; 
std::cout << "after incrementing i1, but not i2\n" 
      << "i1 returns " << *i1 << '\n' 
      << "i2 returns " << *i2 << '\n'; 
++i2; // this makes the apparent value of *i2 to jump from 'a' to 'c' 
std::cout << "after incrementing i2, but not i1\n" 
      << "i1 returns " << *i1 << '\n' 
      << "i2 returns " << *i2 << '\n'; 

} 

Tôi có hai câu hỏi:

  1. Ai đó có thể xây dựng trên mã std::vector<char> v((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());, tôi không hoàn toàn hiểu những gì nó có đang làm .. và tại sao chúng ta có thể in chuỗi "Xin chào, thế giới" chỉ bằng cách sử dụng cout<<&v[0]
  2. Tại sao giá trị học nghề của * i2 nhảy cho "a" đến "c"? ai đó có thể giải thích cơ chế của nó?

Cảm ơn bạn rất nhiều!

Trả lời

10

Ai đó có thể xây dựng trên mã ...

std::vector<T> có một constructor mà mất hai vòng lặp trên <T> - một cho đầu và một cho phần cuối của dãy núi này.

constructor Điều này làm cho một đầu vào dòng iterator từ một input stream in:

std::istreambuf_iterator<char>(in) 

Bạn có thể truy cập vào phần tử của nó đi về phía trước cho đến khi bạn đến cuối của con suối. Một khi bạn đến cuối của dòng, các iterator trở nên tương đương với một iterator tạo bằng cách sử dụng constructor mặc định:

std::istreambuf_iterator<char>() 

Vì vậy, đi qua cặp này lặp xây dựng một vector<T> từ dữ liệu đọc từ một input stream. Toàn bộ luồng sẽ được sử dụng.

Tại sao giá trị học nghề của *i2 nhảy cho ?

Cả hai trình lặp đều đang đọc từ cùng một luồng. Khi bạn tăng bộ lặp đầu tiên, nó sẽ tiêu thụ 'b' từ luồng cơ bản. Trong khi chờ đợi, i2 đề cập đến ký tự đầu tiên của luồng mà nó nhận được mà không cần tiến lên tại thời điểm nó được xây dựng.

Khi bạn tăng i2, nó sẽ hỏi luồng cho ký tự tiếp theo. Ký tự 'b' đã được tiêu thụ, vì vậy ký tự tiếp theo là 'c'.

Cuối cùng, mã kéo một mẹo nhỏ mà bạn có thể đã bỏ qua: nó đẩy một terminator rỗng vào vector<char> để có thể in véc tơ sử dụng quá tải const char* của operator <<(...).

+0

Ngoài ra, làm cách nào để có thể in thư dưới dạng '& v [0]'? :) – 0x499602D2

+0

Vì 'v [0]' là một 'char' nên' & v [0] 'là một' char * ' –

+0

Rất chi tiết! Cảm ơn câu trả lời của bạn!!!! –

2

Mặc định xây dựng istreambuf_iterator về cơ bản là trình lặp cuối tệp, tức là, một trình lặp khác sẽ so sánh bằng chỉ khi nó đến cuối tệp.

Do đó, mã:

std::vector<char> v((std::istreambuf_iterator<char>(in)), 
         std::istreambuf_iterator<char>()); 

...đọc char s từ in cho đến khi vòng lặp đầu tiên được tăng lên bằng với trình lặp thứ hai, xảy ra khi (và chỉ khi) trình vòng lặp đầu tiên đến cuối tệp (chuỗi trong trường hợp này). Tóm lại, nó sao chép toàn bộ nội dung của tệp vào trong vectơ.

Phần "hello world" in đơn giản hơn một chút: ostream có quá tải operator<< cho char *, giả định rằng char * điểm tại một chuỗi kiểu C, vì vậy nó sẽ in toàn bộ chuỗi được chỉ ra. Vì họ đã thực hiện một số push_back để thêm một số '\0' vào chuỗi, làm cho nó trở thành một chuỗi kiểu C.

Phần thứ hai thể hiện rằng mặc dù bạn có hai trình vòng lặp vào luồng, bạn vẫn chỉ có một luồng và một vị trí đọc trong luồng đó. Đồng thời, mỗi trình vòng lặp giữ bản sao của mục gần đây nhất mà nó đọc từ luồng.

Do đó, bất cứ lúc nào bạn tăng hoặc iterator (hoặc bất kỳ iterator vào trong dòng giống nhau) nó increments vị trí đọc hiện nay. Vì vậy, bạn bắt đầu với i1i2 cả hai đều trỏ đến đầu luồng. Sau đó, bạn tăng i1. Điều đó tăng vị trí đọc và đọc b thành i1, vì vậy khi bạn dereference i1, đó là những gì bạn sẽ nhận được. Khi bạn tăng i2, di chuyển vị trí đọc một lần nữa và đọc c vào i2, vì vậy, hãy dereferencing i2 sẽ cung cấp cho c.

Nói tóm lại, việc sử dụng hai (hoặc nhiều hơn) vòng lặp không thay đổi bản chất của con suối - mỗi khi bạn tăng bất kỳ iterator vào cùng một luồng, mà đọc mục tiếp theo từ dòng suối chảy --và "mục tiếp theo" luôn được xác định bởi chính luồng đó, dựa trên một vị trí đọc của nó.

+1

Cảm ơn bạn đã trả lời! Thực sự hữu ích!!! Cảm ơn vì đã dành thời gian cho tôi! –

Các vấn đề liên quan