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

C++ 为什么std::copy(从istream到ostream)会引发ios::failure异常?,c++,stl,stream,C++,Stl,Stream,以下代码应将数据从wifstream复制到wcout。 复制内容后,程序抛出ios::failure异常 #include <string> #include <iostream> #include <sstream> #include <fstream> #include <locale> #include <iterator> #include <algorithm> int main(void) {

以下代码应将数据从wifstream复制到wcout。 复制内容后,程序抛出ios::failure异常

#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;
} 
#包括
#包括
#包括
#包括
#包括
#包括
#包括
内部主(空)
{
std::locale::global(std::locale(“”);
std::wifstream是;
异常(std::ios::failbit | std::ios::badbit);
is.open(“test.ts”,std::ios::binary);
is>>std::noskipws;
(is)中的istream_迭代器;
std::istream_迭代器端;
标准::复制(输入,结束,
std::ostream_迭代器(std::wcout));
返回0;
} 

如果出现问题,流应该只抛出异常(请参阅异常掩码),而不是在EOF上。

为了避免跳过空白,请使用std::istreambuf\u迭代器

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));
std::copy(std::istreambuf_迭代器(is),
std::istreambuf_迭代器(),
std::ostream_迭代器(std::wcout));
例外情况:

本地服务器可能正在使用失败的codecvt方面。
尝试注释区域设置行,看看会发生什么

您是否尝试打印例外情况

try
{
    // do work
}
catch(std::exception const& e)
{
    std::cout << e.what() << "\n";
}
试试看
{
//工作
}
捕获(标准::异常常量和e)
{

std::cout因为您使用的是
std::istream_迭代器
,因此尝试读取流结束后的字符会设置
eofbit
failbit
(只有在设置了一些错误位之后,迭代器才会与结束迭代器相等)

剥离为基本要素并还原为字符以使其更简单,该程序相当于:

#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;
}
#包括
#包括
int main()
{
std::ifstream是(“test.txt”,std::ios::binary);
is.exceptions(std::ios::failbit);//failbit只是因为这是您得到的
is>>std::noskipws;
如果(是)
for(char c;is>>c;)//将抛出!

标准::cout根据§27.6.1.2.3/10:

构造sentry对象后,将从中提取一个字符(如果有),并将其存储在c中。否则,该函数将调用in.setstate(failbit)

因此,当它到达文件末尾并且无法再提取字符时,它将设置失败位,您已将其设置为产生异常。使用
std::copy
不会改变行为--
istream\u迭代器
通过
操作符>
读取

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

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

std::wcout看起来不错,但noskipws不会导致异常。即使我取消注释它,也会出现异常。有一个输入错误,istreambuf_迭代器的第二个参数是一个trait类。异常消息是:basic_ios::clear,即使我删除了全局区域设置,也会引发异常。这对我来说没有任何意义。如果streambuf返回traits_type::eof(),流应该只设置eof位,而不是失败位。如果它说如果设置了eof位,
运算符>>
将返回而不尝试转换,则会发生这种情况,但事实并非如此。即使设置了eof位,它仍会尝试转换,但转换失败,因此失败位被设置。@cytrinox:eofbit已设置,然后op>>导致要设置failbit。不完全等效,但这将是:
for(char c;is>>c;)cout@Roger Pate据我所知,
std::copy
将不会执行
operator>
,即使流已经处于失败状态(并且输入迭代器已经等于结束迭代器),因此在(is)时也不会执行
operator>
。设置流异常似乎是一个好主意,但它通常不会像您预期的那样工作。相反,只需在使用输入之前检查流状态,例如
if(stream>>var){/*now use var*/}