Boost buffer_cast cannot convert from void* to PointerToPodType

Viewed 229

I am interested in Socket communication and use boost library. When i got a message from server and try to convert it atomic<uint8_t>* it gaves me an error that 'static_cast': cannot convert from 'const void*' to 'PointerToPodType'. I could not understand why it gaves me that error.

Code sample

atomic<uint8_t>* buffer = new atomic<uint8_t>[10000];

boost::asio::streambuf receive_buffer;
boost::asio::read(*sock, receive_buffer, boost::asio::transfer_all(), this->ec);
    if (this->ec && this->ec != boost::asio::error::eof) {

        cout << "receive failed:" << this->ec.message() << endl;
    }
    else
    {
        ///ERROR IS HERE
        buffer = boost::asio::buffer_cast< atomic<uint8_t>*>(receive_buffer.data());

    }
1 Answers

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.

Related