【问题标题】:Read vector<char> as stream将 vector<char> 读取为流
【发布时间】:2014-05-13 11:46:24
【问题描述】:

我有一个 CONST 向量,但需要一个函数来读取它。问题是,该函数需要一个 istream。

将向量内的数据传递给此函数的最有效方法是什么?

我尝试了这种方法来防止复制流,但它不起作用,因为我的向量是 const 并且 pubsetbuf 需要一个非 const char *。

istringstream is;
const vector<char>& data = GETDATA();
is.rdbuf()->pubsetbuf(&data[0], data.size());

由于流是只读的,我可以转换指针。那安全吗? 或者有什么更好的方法?

【问题讨论】:

  • @luk32 不,这是为了工作:(

标签: c++ stl


【解决方案1】:

考虑使用Boost.Iostreams

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

using namespace boost::iostreams;
stream<array_source> bs(data.data(), data.size());
std::istream &is = bs;

【讨论】:

    【解决方案2】:

    您可以编写自己的流:

    #include <algorithm>
    #include <ostream>
    
    // BasicSequenceInputBuffer
    // ============================================================================
    
    template < typename Char, typename Traits = std::char_traits<Char> >
    class BasicSequenceInputBuffer
    :   public std::basic_streambuf<Char, Traits>
    {
        // Types
        // =====
    
        private:
        typedef std::basic_streambuf<Char, Traits> Base;
    
        public:
        typedef typename Base::char_type char_type;
        typedef typename Base::int_type int_type;
        typedef typename Base::pos_type pos_type;
        typedef typename Base::off_type off_type;
        typedef typename Base::traits_type traits_type;
        typedef const char_type* pointer;
        typedef std::size_t size_type;
    
        // Construction
        // ============
    
        public:
        BasicSequenceInputBuffer(pointer data, size_type size) {
            // These casts are safe (no modification will take place):
            char* begin = const_cast<char_type*>(data);
            char* end = const_cast<char_type*>(data + size);
            this->setg(begin, begin, end);
        }
    
        // Stream Buffer Interface
        // =======================
    
        protected:
        virtual std::streamsize showmanyc();
        virtual std::streamsize xsgetn(char_type*, std::streamsize);
        virtual int_type pbackfail(int_type);
    
        // Utilities
        // =========
    
        protected:
        int_type eof() { return traits_type::eof(); }
        bool is_eof(int_type ch) { return ch == eof(); }
    };
    
    
    // Get Area
    // ========
    
    template <typename Char, typename Traits>
    std::streamsize
    BasicSequenceInputBuffer<Char, Traits>::showmanyc() {
        return this->egptr() - this->gptr();
    }
    
    template <typename Char, typename Traits>
    std::streamsize
    BasicSequenceInputBuffer<Char, Traits>::xsgetn(char_type* p, std::streamsize n) {
        std::streamsize result = std::min(n, this->egptr() - this->gptr());
        std::copy(this->gptr(), this->gptr() + result, p);
        this->gbump(result);
        return result;
    }
    
    template <typename Char, typename Traits>
    typename BasicSequenceInputBuffer<Char, Traits>::int_type
    BasicSequenceInputBuffer<Char, Traits>::pbackfail(int_type ch) {
        if(is_eof(ch)) {
            if(this->eback() != this->gptr()) {
                this->gbump(-1);
                return traits_type::to_int_type(*this->gptr());
            }
        }
        return eof();
    }
    
    typedef BasicSequenceInputBuffer<char> SequenceInputBuffer;
    
    
    // BasicSequenceInputStream
    //=============================================================================
    
    template < typename Char, typename Traits = std::char_traits<Char> >
    class BasicSequenceInputStream
    :   public std::basic_istream<Char, Traits>
    {
        private:
        typedef std::basic_istream<Char, Traits> Base;
    
        public:
        typedef typename Base::char_type char_type;
        typedef typename Base::int_type int_type;
        typedef typename Base::pos_type pos_type;
        typedef typename Base::off_type off_type;
        typedef typename Base::traits_type traits_type;
    
        private:
        typedef BasicSequenceInputBuffer<Char, Traits> buffer_type;
    
        public:
        typedef typename buffer_type::pointer pointer;
        typedef typename buffer_type::size_type size_type;
    
        // Construction
        // ============
    
        public:
        explicit BasicSequenceInputStream(pointer data, size_type size)
        :   Base(&m_buf), m_buf(data, size)
        {}
    
        private:
        buffer_type m_buf;
    };
    
    typedef BasicSequenceInputStream<char> SequenceInputStream;
    
    
    // Test
    // ====
    
    #include <iostream>
    #include <vector>
    
    int main()
    {
        const std::string s = "Hello World";
        const std::vector<char> vector(s.begin(), s.end());
        SequenceInputStream stream(vector.data(), vector.size());
    
        std::string line;
        std::getline(stream, line);
        std::cout << line << '\n';
    }
    

    【讨论】:

    • 感谢您为回答所付出的努力。但我想我只会复制向量。
    • @NeilKirk 注意:这里没有复制(序列的开始和结束存储在现有的流指针中)。但如果内存(大小)没有问题,那么普通副本是合理且足够好的。
    猜你喜欢
    • 2014-05-16
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多