代码之家  ›  专栏  ›  技术社区  ›  cytrinox

为什么std::copy(从istream到ostream)会引发ios::failure异常?

  •  8
  • cytrinox  · 技术社区  · 14 年前

    以下代码应将数据从wifstream复制到wcout。

    #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;
    } 
    

    流只应在出现问题时抛出异常(请参阅异常掩码),但不应在EOF上抛出异常。

    3 回复  |  直到 14 年前
        1
  •  1
  •   Loki Astari    14 年前

    要避免跳过空白,请使用std::istreambuf_迭代器

    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));
    

    本地可能正在使用失败的codecvt方面。
    尝试注释掉语言环境行,看看会发生什么。

    try
    {
        // do work
    }
    catch(std::exception const& e)
    {
        std::cout << e.what() << "\n";
    }
    
        2
  •  1
  •   Cubbi    14 年前

    因为你在用 std::istream_iterator ,尝试读取超过流结尾的字符将同时设置 eofbit failbit

    剥离到基本组件并还原为char以使其更简单,程序相当于:

    #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;
    }
    
        3
  •  0
  •   Jerry Coffin    14 年前

    根据第27.6.1.2.3/10节:

    在里面 ,如果有,则存储在 c类 输入设置状态(故障位) .

    std::copy 不会改变你的行为 istream_iterator operator>> .

    您可以更轻松地复制文件:

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