How can I specify the boost::asio::streambuf bufferstrm size globally

281 views Asked by At

I know that we can specify the size of streambuf as below in some function

boost::asio::streambuf bufferstrm(512);

but in class how can we do the same thing

class test{
      public:
          boost::asio::streambuf bufferstrm;
      void func1(){
          //statement
      }
      void func2(){
          //statement
      }
};

So my question is if we are having boost::asio::streambuf bufferstrm; declared in above class then how can we specify the size of bufferstrm so that it can be available to all the functions of the class.

I tried below code

class test{
      public:
          boost::asio::streambuf bufferstrm(1024);  // specified the size
      void func1(){
          //statement
      }
      void func2(){
          //statement
      }
};

But its giving error as cant initialize at the declaration point.

1

There are 1 answers

2
sehe On

You can use NSMI with the correct syntax in C++14 and up:

class test {
  public:
    boost::asio::streambuf bufferstrm { 1024 }; 

In fact, this is nothing but a shorthand for a constructor initializer list item, in c++03 style:

class test {
  public:
    boost::asio::streambuf bufferstrm;

    test()
       : bufferstrm (1024) // base/member initializer list
    {}

Subclass

You can also consider creating a derived type that adds the initialization.

UPDATE Subclass idea

It turns out not so simple to make a subclass actually work with API's consuming streambuf as all the API's perform type-deduction on the buffer argument. Type deduction doesn't consider the conversion-to-base, so it fails to recognizes classes derived from streambuf. Also, you need those overloads as streambuf is the only buffer type that is taken by reference.

I can see two solutions:

  1. provide a conversion to basic_streambuf_ref<>
  2. hack it by specializing basic_streambuf<myalloc> for an artificial allocator type just to add the initialization semantics.

Conversion to basic_streambuf_ref<>

You'll have to call it explicitly, but that's perhaps not the worst:

struct mystreambuf : boost::asio::streambuf
{
    using base_type = boost::asio::streambuf;
    mystreambuf() : base_type{1024} {}

    auto ref()
    {
        return boost::asio::basic_streambuf_ref<std::allocator<char>>{
            *static_cast<base_type*>(this)};
    }
};

Used as:

using boost::asio::ip::tcp;
tcp::socket sock(boost::asio::system_executor{}, {{}, 7878});

mystreambuf msb;
read_until(sock, msb.ref(), "\r\n\r\n");

See it on Compiler Explorer

Hacked allocator

template <typename T>
struct myalloc : std::allocator<T> {};

template <typename T>
struct boost::asio::basic_streambuf<myalloc<T>>
    : boost::asio::basic_streambuf<std::allocator<T>>
{
    basic_streambuf() : base_type(1024) {}

    using base_type = boost::asio::basic_streambuf<std::allocator<T>>;
    using base_type::base_type;
    using base_type::operator=;
};

using mystreambuf1024 = boost::asio::basic_streambuf<myalloc<char>>;

Which can then be used as

mystreambuf1024 msb;
read_until(sock, msb, "\r\n\r\n");

See it Compiler Explorer