2011-12-04 29 views
7

Làm cách nào để thực hiện điều này bằng thuật toán STL?copy_n hoặc cho đến eof?

std::ifstream file(filename); 

std::vector<unsigned char> buf; 
for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 2048; ++file_it) 
    buf.push_back(*file_it); 

Lưu ý buf.size() < 2048.

ví dụ: điều gì sẽ xảy ra nếu tôi làm như sau và tệp nhỏ hơn 2048 byte?

std::copy_n(std::istreambuf_iterator<char>(file), 2048, std::back_inserter(buf)); 
+0

Điều gì xảy ra nếu tệp lớn hơn? Là phần còn lại của nó bị loại bỏ hoặc bạn cần một iterator để bắt đầu của phần còn lại để được đọc? – pmr

+0

Ifstream bị hủy bỏ khi số byte yêu cầu đã được đọc. – ronag

+0

Điều này mở ra khả năng có một trình lặp riêng biệt thay vì một thuật toán. – pmr

Trả lời

1

Giống như các tài liệu nói, std::copy_n() sẽ sao chép chính xácn mục. Nó sẽ tiếp tục đọc qua cuối trình tự mà trình vòng lặp đề cập đến. Tôi không chắc chắn những gì tiêu chuẩn nói về istreambuf_iterator<>, mặc dù. Đó có thể là hành vi không xác định, nhưng các luồng có khả năng tạo ra rất nhiều bản sao của eof() trong quá khứ. Điều này có thể dẫn đến nhiều rác khi có ít hơn 2048 byte khả dụng.

Trong mọi trường hợp, nếu bạn muốn chắc chắn sao chép lên đếnn mục, bạn sẽ cần phải viết chức năng riêng của bạn:

template<typename I1, typename I2, typename size_type> 
I copy_upto_n (I1 begin, I1 end, size_type n, I2 out) 
{ 
    for (size_type i=0; (i < n) && (begin != end); ++i) 
    { 
     *out++ = *begin++; 
    } 
    return out; 
} 

Một số người có thể sử dụng std::iterator_traits<> thay vì một mẫu tham số thêm để buộc cùng một loại khoảng cách như trình lặp.

+0

+1 Đối với thuật toán lặp chung và đề cập đến 'std :: iterator_traits'. –

+0

'out' có thể là đối số mẫu riêng biệt. – pmr

+0

@pmr: Thật vậy. Nếu không có điều đó, nó sẽ không hoạt động đối với trường hợp sử dụng được đăng trong câu hỏi (ví dụ: sử dụng 'std :: back_inserter()'). Tôi sẽ chỉnh sửa mã. –

0

Bạn có thể sử dụng back_insert_iterator đặc biệt để loại bỏ các hoạt động dựa trên vị từ.

Mã này đã được biết xấu hổ lấy từ việc triển khai GCC phần cứng và được điều chỉnh. Phiên bản C++ 03 chỉ yêu cầu Container::const_reference trong bài tập.

template<typename Container, typename Predicate> 
class discarding_back_inserter 
    : public iterator<output_iterator_tag, void, void, void, void> 
{ 
    Container* container; 
    Predicate p; 
public: 
    typedef Container   container_type; 

    explicit 
    back_insert_iterator(Container& x, Predicate p) : container(&__x), p(p) { } 

    back_insert_iterator& 
    operator=(const typename Container::value_type& value) 
    { 
     if(*container) 
     container->push_back(__value); 
     return *this; 
    } 

    back_insert_iterator& 
    operator=(typename _Container::value_type&& value) 
    { 
     if(*container) 
     container->push_back(std::move(__value)); 
     return *this; 
    } 

    back_insert_iterator& 
    operator*() 
    { return *this; } 

    back_insert_iterator& 
    operator++() 
    { return *this; } 

    back_insert_iterator 
    operator++(int) 
    { return *this; } 
}; 
+1

Đừng dùng cá nhân này, nhưng, eww. –

+0

@BenjaminLindley Nah, không bao giờ. Tôi chỉ mặc dù nó có giá trị để tìm cách tiếp cận đối diện để sửa đổi các thuật toán. Kết quả không phải là mục đích rất chung vì nó hoạt động trên hộp chứa. Tôi thực sự muốn có một phiên bản 'generate' dựa trên giá trị' Maybe'. Điều đó sẽ làm cho điều này thực sự dễ dàng. – pmr

+0

Điều này không sử dụng biến vị ngữ. Nó có thể hoạt động nếu vị từ đã lưu một con trỏ tới luồng, để nó có thể kiểm tra eof. Đối số giá trị sẽ không cung cấp nhiều thông tin. – UncleBens

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