繁体   English   中英

boost :: iostreams :: copy()关闭源但不关闭接收器

[英]boost::iostreams::copy() closes the source but not the sink

我试图使用boost :: iostreams来压缩数据。

copy()的doc说它的两个参数最后通过在它们上面调用模板函数close()关闭 我的测试代码是:

#include <iostream>
#include <fstream>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

using namespace std;

int main(void)
{
    ifstream ifs("output", ios::binary);
    ofstream ofs("output.boost.gz", ios::binary);

    boost::iostreams::filtering_streambuf<boost::iostreams::output> out;

    out.push(boost::iostreams::gzip_compressor());
    out.push(ofs);

    cout << (ifs.is_open() ? "ifs is opened" : "ifs not opened") << endl;
    cout << (ofs.is_open() ? "ofs is opened" : "ofs not opened") << endl;

    boost::iostreams::copy(ifs, out);

    cout << (ifs.is_open() ? "ifs is opened" : "ifs not opened") << endl;
    cout << (ofs.is_open() ? "ofs is opened" : "ofs not opened") << endl;

    return 0;
}

该测试输出:

ifs is opened
ofs is opened
ifs not opened
ofs is opened

你可以看到仍然打开了。 我的问题是:为什么? boost :: iostreams :: close()在传递filtering_streambuf对象时做了什么?

有趣。

走下兔子洞[1] ,结果发现最终到达了close_impl<any_tag> ,因为ofstream包裹在filtering_streambuf里面的chain_buf深处。 实现如下:

template<>
struct close_impl<any_tag> {
    template<typename T>
    static void close(T& t, BOOST_IOS::openmode which)
    {
        if (which == BOOST_IOS::out)
            iostreams::flush(t);
    }

    template<typename T, typename Sink>
    static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
    {
        if (which == BOOST_IOS::out) {
            non_blocking_adapter<Sink> nb(snk);
            iostreams::flush(t, nb);
        }
    }
};

因此,正如您所看到的,记录的行为实际上只是链接的输出流缓冲区被刷新(在该调用之前,包含的实体上也存在同步,IIRC)。

我完全同意这可以更加明确。

阅读决定专业化的TMP代码:

template<typename T>
struct close_tag {
    typedef typename category_of<T>::type             category;
    typedef typename detail::unwrapped_type<T>::type  unwrapped;
    typedef typename
            iostreams::select<
                mpl::not_< is_convertible<category, closable_tag> >,
                any_tag,
                mpl::or_<
                    is_boost_stream<unwrapped>,
                    is_boost_stream_buffer<unwrapped>
                >,
                close_boost_stream,
                mpl::or_<
                    is_filtering_stream<unwrapped>,
                    is_filtering_streambuf<unwrapped>
                >,
                close_filtering_stream,
                mpl::or_<
                    is_convertible<category, two_sequence>,
                    is_convertible<category, dual_use>
                >,
                two_sequence,
                else_,
                closable_tag
            >::type type;
};

我想到了几种解决方法:

  1. std::ofstream定义一个close_tag<> ,它实际上返回一个不同的标签,然后使它关闭(我建议不要这样做,因为它可以通过违反Boost Iostreams开发者的假设而产生意想不到的效果)

  2. 为输出流使用boost类:

#include <iostream>
#include <fstream>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>

using namespace std;

int main(void)
{
    cout << boolalpha;

    ifstream ifs("output", ios::binary);
    boost::iostreams::file_sink ofile("output.boost.gz");

    boost::iostreams::filtering_streambuf<boost::iostreams::output> out;
    out.set_auto_close(true);

    out.push(boost::iostreams::gzip_compressor());
    out.push(ofile);

    cout << "out.is_complete(): " << out.is_complete() << endl;
    cout << "ifs.is_open()? "     << ifs.is_open()     << endl;
    cout << "ofile.is_open()? "   << ofile.is_open()   << endl;

    boost::iostreams::copy(ifs, out);

    cout << "out.is_complete(): " << out.is_complete() << endl;
    cout << "ifs.is_open()? "     << ifs.is_open()     << endl;
    cout << "ofile.is_open()? "   << ofile.is_open()   << endl;
}

在科利鲁看到它


[1]我必须补充说,这是一个令人惊讶的大兔子洞。 我想知道这些通用性真正有什么好处

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM