为现有缓冲区提供std :: istream接口而不复制它

时间:2011-03-20 19:56:25

标签: c++ iostream

我有一个固定长度的字符缓冲区,我想将它提供给一个带有std :: istream&的函数。如果不复制缓冲区,我怎么能这样做?

如果这意味着派生出一个自定义的streambuf,我想我会接受这个副本。我只是想知道我是否遗漏了一些直截了当的东西。

这就是我现在正在做的事情(这是不需要的副本):

void loadFromBuffer(const char* buff, size_t len) {
    std::istringstream is(std::string(buff, len)); // BUFFER COPIED HERE :(
    load(is);
}

修改

对于记录,这是使用boost.Iostreams的简单解决方案:

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

void loadFromBuffer2(char* buff, size_t len) {
    typedef boost::iostreams::stream<boost::iostreams::array_source> array_stream;
    array_stream is(buff, len);
    load(is);
}

我接受了Boost.Iostreams的答案,因为它似乎是“正确的”解决方案,但它不能在我的平台(Android NDK)上编译,所以我最终使用了弃用的std :: istrstream解决方案。谢谢大家。

3 个答案:

答案 0 :(得分:7)

我自己也处于类似情况,而不是自己创建所有内容Boost.Iostreams,而是创建一个只读源设备。

未经测试,但这可能有效:

class ConstBufferDevice
{
public:
   typedef char char_type;

   struct category :
      virtual boost::iostreams::device_tag,
      virtual boost::iostreams::input_seekable
   {
   };

   ConstBufferDevice(const char_type* buffer, size_t buffersize)
      : buffer_(buffer)
      , buffersize_(buffersize)
      , pos_(0)
   {
   }

   std::streamsize read(char_type* buffer, std::streamsize buffersize)
   {
      const std::streamsize amount = static_cast<std::streamsize>(buffersize_ - pos_);
      const std::streamsize result = (std::min)(buffersize, amount);
      if (result != 0)
      {
         std::copy(buffer_ + pos_, buffer_ + pos_ + result, buffer);
         pos_ += result;
         return result;
      }
      else
      {
         return buffersize ? -1 : 0; // EOF
      }
   }

   std::streampos seek(boost::iostreams::stream_offset offset,
                       std::ios_base::seekdir seekdir)
   {
      // Determine new value of pos_
      boost::iostreams::stream_offset newpos;

      if (seekdir == std::ios_base::beg)
      {
         newpos = offset;
      }
      else if (seekdir == std::ios_base::cur)
      {
         newpos = pos_ + offset;
      }
      else if (seekdir == std::ios_base::end)
      {
         newpos = buffersize_ + offset;
      }
      else
      {
         throw std::ios_base::failure("bad seek direction");
      }

      // Check for errors
      if (newpos < 0 || newpos > buffersize_)
      {
         throw std::ios_base::failure("bad seek offset");
      }

      pos_ = static_cast<size_t>(newpos);
      return boost::iostreams::offset_to_position(newpos);
   }

private:
   const char_type* buffer_;
   size_t buffersize_;
   size_t pos_;
};

typedef boost::iostreams::stream<ConstBufferDevice> ConstBufferStream;

答案 1 :(得分:1)

一种选择是提供引用外部(而不是内部)缓冲区的std::streambuf自定义实现。完成后,您可以继承std::istream并提供一个构造函数,将istream的流缓冲区设置为指向缓冲区的自定义streambuf类型的实例。这会立即为您提供由外部缓冲区支持的istream的完整功能。 IIRC,实现streambuf的大部分复杂性涉及在数据耗尽时重新填充缓冲区的复杂性,但在您的情况下,这应该是微不足道的,因为您只能报告您没有数据。

希望这有帮助!

答案 2 :(得分:1)

我怀疑这是可能的。 STL容器/流等总是希望拥有缓冲区,因此它们会复制它。我没有简单的方法。