It's not C, don't use new, malloc (or delete or free).
Specically, I see pointers to sockets, pointers to everything. You leak the entire buffer allocated with new if you made the assignment work.
Here's a simpler take, cutting the double-buffering (streambuf adds little):
uint8_t buffer[10000];
auto transferred = boost::asio::read(
sock,
boost::asio::buffer(buffer),
boost::asio::transfer_all(),
ec);
Now on success, tranferred bytes will be inside your allocated buffer already. Even simpler with a
std::vector<uint8_t> buffer(10000);
Because then you can simply
buffer.resize(transferred);
Live On Coliru
#include <boost/asio.hpp>
#include <atomic>
#include <iostream>
#include <iomanip>
using boost::asio::ip::tcp;
using boost::asio::ip::address_v4;
int main() {
//uint8_t buffer[10000];
std::vector<uint8_t> buffer(10000);
boost::asio::io_context ioc;
tcp::socket sock(ioc);
sock.connect({address_v4::from_string("173.203.57.63"), 80});
write(sock, boost::asio::buffer("GET / HTTP/1.1\r\nHost: coliru.stacked-crooked.com\r\nConnection: close\r\n\r\n"));
boost::system::error_code ec;
auto transferred = boost::asio::read(
sock,
boost::asio::buffer(buffer),
boost::asio::transfer_all(),
ec);
if (ec && ec != boost::asio::error::eof) {
std::cout << "receive failed:" << ec.message() << std::endl;
} else {
buffer.resize(transferred);
std::cout << std::hex << std::showbase << std::setfill('0');
int n = 0;
for (int i : buffer) {
std::cout
<< std::setw(4) << i
<< " '" << char(std::isgraph(i)?i : '.') << "'"
<< (++n % 8? ' ':'\n');
}
}
}
Prints
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
0x48 'H' 0x54 'T' 0x54 'T' 0x50 'P' 0x2f '/' 0x31 '1' 0x2e '.' 0x31 '1'
0x20 '.' 0x32 '2' 0x30 '0' 0x30 '0' 0x20 '.' 0x4f 'O' 0x4b 'K' 0x20 '.'
00xd '.' 00xa '.' 0x43 'C' 0x6f 'o' 0x6e 'n' 0x74 't' 0x65 'e' 0x6e 'n'
0x74 't' 0x2d '-' 0x54 'T' 0x79 'y' 0x70 'p' 0x65 'e' 0x3a ':' 0x20 '.'
0x74 't' 0x65 'e' 0x78 'x' 0x74 't' 0x2f '/' 0x68 'h' 0x74 't' 0x6d 'm'
... 1100 lines snipped
0x20 '.' 0x20 '.' 0x7d '}' 0x3b ';' 00xa '.' 0x3c '<' 0x2f '/' 0x73 's'
0x63 'c' 0x72 'r' 0x69 'i' 0x70 'p' 0x74 't' 0x3e '>' 00xa '.' 0x3c '<'
0x2f '/' 0x68 'h' 0x74 't' 0x6d 'm' 0x6c 'l' 0x3e '>' 00xa '.'
Dynamic/Heap allocation
std::vector already does heap allocation. I you insist on the raw C array semantics, consider Live On Coliru:
auto buffer = std::make_unique<std::array<std::atomic<uint8_t, 10'000> > >();
// ...
boost::asio::buffer(*buffer),
// ...
size_t n = 0;
for (int i : *buffer) {
if (n>=transferred) break;
std::cout
<< std::setw(4) << i
<< " '" << char(std::isgraph(i)?i : '.') << "'"
<< (++n % 8? ' ':'\n');
}
Or even Live On Coliru:
auto buffer = std::make_unique<uint8_t[]>(10'000);
// ...
boost::asio::buffer(buffer.get(), 10'000),
// ...
size_t n = 0;
for (auto it = buffer.get(); it <= buffer.get() + transferred; ++it) {
std::cout
<< std::setw(4) << static_cast<int>(*it)
<< " '" << char(std::isgraph(*it)?*it : '.') << "'"
<< (++n % 8? ' ':'\n');
}
As you can see the operation with "manual" buffers like this is much more error-prone, but at least now you donot have a memory leak.