0

Usually I use this technique using shared pointers for managing the lifetime of my buffers used in asynchronous operations with boost.asio.

What if my buffer is a std::string object (which I guess is a little bit special because it does some internal reference counting or so)? Do I still need a shared pointer of a string object which I pass to the handler of the asynchronous operation? Or is the following safe? (And why / why not ?)

void handler()
{
}

void func()
{
    std::ostringstream stringbuilder;
    // fill stringbuilder

    socket.async_send(boost::asio::buffer(stringbuilder.str()), boost:bind(handler));
}
Community
  • 1
  • 1
Robert Hegner
  • 9,014
  • 7
  • 62
  • 98

1 Answers1

2

Even though std::string may be internally reference counted, the underlying memory managed by std::string must remain valid throughout the duration of the asynchronous operation. The earliest it can be destroyed is at the start of the handler. Often, a shared_ptr is used to extend the lifetime of the buffer so that it remains valid throughout the asynchronous operation.

Per the documentation:

One or more buffers containing the data to be written. Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.

In this particular case, boost::asio::buffer() takes the string by reference. Thus, any internal reference counting will not occur.

template<
    typename Elem,
    typename Traits,
    typename Allocator>
const_buffers_1 buffer(
    const std::basic_string< Elem, Traits, Allocator > & data);

Once the socket.async_send(...) statement returns, the temporary std::string returned from stringbuilder.str() is destroyed, and invalidates the lifetime requirement for asynchronous operation's buffer.

Tanner Sansbury
  • 51,153
  • 9
  • 112
  • 169