2010-11-04 23 views
8

Đoạn mã sau nên sao chép dữ liệu từ wifstream đến wcout. Sau khi nội dung được sao chép, chương trình sẽ ném ngoại lệ lỗi ios ::.Tại sao std :: copy (từ istream đến ostream) làm tăng ios :: failure exception?

#include <string> 
#include <iostream> 
#include <sstream> 
#include <fstream> 
#include <locale> 
#include <iterator> 
#include <algorithm> 


int main(void) 
{ 
    std::locale::global(std::locale("")); 

    std::wifstream is; 
    is.exceptions(std::ios::failbit | std::ios::badbit); 
    is.open("test.ts", std::ios::binary); 

    is >> std::noskipws; 

    std::istream_iterator<wchar_t, wchar_t> in(is); 
    std::istream_iterator<wchar_t, wchar_t> end; 

    std::copy(in, end, 
       std::ostream_iterator<wchar_t, wchar_t>(std::wcout)); 

    return 0; 
} 

Luồng chỉ nên ném ngoại lệ (xem mặt nạ ngoại lệ) nếu có gì xấu, nhưng không phải trên EOF.

+0

dòng Setting trường hợp ngoại lệ có vẻ như là một ý tưởng tốt, nhưng nó thường không hoạt động như bạn mong đợi. Thay vào đó, chỉ cần kiểm tra trạng thái luồng trước khi sử dụng dữ liệu nhập, ví dụ: 'if (stream >> var) {/ * chỉ sử dụng var * /}'. –

Trả lời

1

Để tránh bỏ qua khoảng trắng sử dụng std :: istreambuf_iterator

std::copy(std::istreambuf_iterator<wchar_t, wchar_t>(is), 
      std::istreambuf_iterator<wchar_t, wchar_t>(), 
      std::ostream_iterator<wchar_t, wchar_t>(std::wcout)); 

Trường hợp ngoại lệ:

Các địa phương có thể được sử dụng codecvt khía cạnh đó là thất bại.
Thử nhận xét ra dòng địa phương xem điều gì xảy ra.

Bạn đã cố gắng in những ngoại lệ là gì?

try 
{ 
    // do work 
} 
catch(std::exception const& e) 
{ 
    std::cout << e.what() << "\n"; 
} 
+0

Có vẻ đẹp, nhưng noskipws không gây ra ngoại lệ. Ngay cả khi tôi bỏ ghi chú, có một ngoại lệ. – cytrinox

+0

Có lỗi đánh máy, đối số thứ hai của istreambuf_iterator là một lớp đặc điểm. – cytrinox

+0

Thông báo ngoại lệ là: basic_ios :: clear và ngay cả khi tôi xóa ngôn ngữ toàn cục, ngoại lệ được ném. – cytrinox

1

Bởi vì bạn đang sử dụng std::istream_iterator, nỗ lực để đọc một nhân vật quá khứ cuối dòng đặt cả eofbitfailbit (và chỉ sau khi một số bit lỗi được thiết lập, không biến lặp trở thành tương đương với iterator cuối)

Tước đến yếu tố cần thiết để trần và quay trở lại char để làm cho nó thậm chí còn đơn giản hơn, chương trình tương đương với:

#include <iostream> 
#include <fstream> 
int main() 
{ 
    std::ifstream is("test.txt", std::ios::binary); 
    is.exceptions(std::ios::failbit); // failbit only because that's what you get 
    is >> std::noskipws; 
    if(is) 
     for(char c; is >> c;) // will throw! 
      std::cout << c; 
} 
+0

Không hoàn toàn tương đương, nhưng điều này sẽ là: 'for (char c; is >> c;) cout << c;' –

+0

@Roger Pate Theo như tôi hiểu, 'std :: copy' sẽ không thực thi' toán tử> > 'ngay cả khi luồng đã ở trạng thái không thành công (và trình lặp đầu vào đã bằng với trình lặp kết thúc) do đó trong khi (là). – Cubbi

+0

Ah, bạn nói đúng: 'if (is) cho (char c; is >> c;) ...' –

0

Theo §27.6.1.2.3/10:

Sau khi đối tượng sentry được xây dựng, ký tự được trích xuất từ ​​trong, nếu có sẵn và được lưu trữ trong c. Nếu không, hàm sẽ gọi in.setstate (failbit).

Vì vậy, khi đến cuối tệp và không thể trích xuất ký tự nữa, nó sẽ đặt bit lỗi mà bạn đã đặt để tạo ngoại lệ. Sử dụng std::copy không thay đổi hành vi - số istream_iterator lần đọc qua operator>>.

Bạn có thể sao chép các tập tin một cách dễ dàng hơn một chút:

std::wifstream is("test.ts", std::ios::binary); 
std::wcout << is.rdbuf(); 
+0

Nó không có ý nghĩa với tôi.Nếu streambuf underlaying trả về traits_type :: eof(), luồng chỉ nên đặt bit eof, bit không bị lỗi. – cytrinox

+0

Nếu nó nói rằng 'toán tử >>' sẽ trả về mà không thử chuyển đổi nếu bit eof được thiết lập, thì điều đó sẽ xảy ra - nhưng nó không xảy ra. Ngay cả khi bit eof được đặt, nó vẫn cố gắng chuyển đổi, không thành công, do đó bit không thành công được đặt. –

+0

@cytrinox: eofbit được đặt và sau đó op >> gây ra failbit được đặt. –

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