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

发布于 2024-09-30 19:45:08 字数 767 浏览 0 评论 0原文

以下代码应将数据从 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;
} 

如果出现任何问题,流应该仅抛出异常(请参阅异常掩码),但不会在 EOF 时抛出异常。

The following code should copy data from an wifstream to wcout.
After the content is copied, the program throws a 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;
} 

The stream should only throw an exception (see exception mask) if anything goes bad, but not on EOF.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

沫尐诺 2024-10-07 19:45:08

为了避免跳过空白,请使用 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));

例外:

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

您是否尝试过打印异常情况?

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

To avoid skipping white space use the 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));

The exception:

The local may be using codecvt facet that is failing.
Try commenting out the locale line see what happens.

Have you tried to print what the exceptions is?

try
{
    // do work
}
catch(std::exception const& e)
{
    std::cout << e.what() << "\n";
}
遗弃M 2024-10-07 19:45:08

由于您使用的是 std::istream_iterator,因此尝试读取流末尾之后的字符会同时设置 eofbitfailbit(并且只有在设置了一些错误位之后,迭代器才变得等于结束迭代器)

剥离到最基本的部分并恢复为 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;
}

Because you're using std::istream_iterator, the attempt to read a character past the end of the stream sets both eofbit and failbit (and only after some error bits are set, does the iterator become equal to the end iterator)

Stripping to bare essentials and reverting to char to make it even simpler, program is equivalent to:

#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;
}
梦晓ヶ微光ヅ倾城 2024-10-07 19:45:08

根据§27.6.1.2.3/10:

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

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

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

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

According to §27.6.1.2.3/10:

After a sentry object is constructed a character is extracted from in, if one is available, and stored in c. Otherwise, the function calls in.setstate(failbit).

So, when it reaches the end of the file and can no longer extract a character, it will set the fail bit, which you've set to produce an exception. Using std::copy doesn't change the behavior -- an istream_iterator reads via operator>>.

You can copy the file a bit more easily:

std::wifstream is("test.ts", std::ios::binary);
std::wcout << is.rdbuf();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文