0

I'm working on Asynchronous networking code for use in a library, and my code designed to 'send' data works pretty flawlessly:

//connection_id is a wrapper around a size_t
//data_vector is an alias for std::vector<unsigned char>
bool write_to_connection(const connection_id & id, const data_vector & data) {
    if (connections.contains(id)) {
        std::shared_ptr<data_vector> write_buffer = std::make_shared<data_vector>(data);
        connection_ptr conn = connections[id];
        conn->get_socket().async_write_some(
            boost::asio::buffer(
                *write_buffer
                ),
            std::bind(
                &basic_server::write,
                this,
                std::placeholders::_1,
                std::placeholders::_2,
                id,
                write_buffer
            )
        );
        return true;
    }
    return false;
}

void write(const boost::system::error_code & ec, size_t bytes_written, const connection_id & id, std::shared_ptr<data_vector> write_buffer) {
    if (ec) {
        connections.erase(id);
    }
}

However, for performance reasons, I don't like the use of std::shared_ptr to maintain my data, especially since I might be issuing many, many of these callbacks at once. I don't even use it in the callback function, and only add it to ensure that the data buffer's lifetime lasts until the write completes.

I'd like to use std::unique_ptr, since I only logically need one copy of the object at any given time, which gets passed along (read: moved) to the callback function, which I've written like this:

//connection_id is a wrapper around a size_t
//data_vector is an alias for std::vector<unsigned char>
bool write_to_connection(const connection_id & id, const data_vector & data) {
    if (connections.contains(id)) {
        std::unique_ptr<data_vector> write_buffer = std::make_unique<data_vector>(data);
        connection_ptr conn = connections[id];
        conn->get_socket().async_write_some(
            boost::asio::buffer(
                *write_buffer
                ),
            std::bind(
                &basic_server::write,
                this,
                std::placeholders::_1,
                std::placeholders::_2,
                id,
                std::move(write_buffer) //So that we're not performing a copy; we're performing a move
            )
        );
        return true;
    }
    return false;
}

void write(const boost::system::error_code & ec, size_t bytes_written, const connection_id & id, std::unique_ptr<data_vector> write_buffer) {
    if (ec) {
        connections.erase(id);
    }
}

However, this promptly gives me this (quite verbose) compile error:

Error   C2280   'std::_Binder<std::_Unforced,void (__cdecl server::basic_server::* )(const boost::system::error_code &,size_t,const server::connection_id &,std::unique_ptr<server::data_vector,std::default_delete<_Ty>>),server::basic_server *const ,const std::_Ph<1> &,const std::_Ph<2> &,const server::connection_id &,std::unique_ptr<_Ty,std::default_delete<_Ty>>>::_Binder(const std::_Binder<std::_Unforced,void (__cdecl server::basic_server::* )(const boost::system::error_code &,size_t,const server::connection_id &,std::unique_ptr<_Ty,std::default_delete<_Ty>>),server::basic_server *const ,const std::_Ph<1> &,const std::_Ph<2> &,const server::connection_id &,std::unique_ptr<_Ty,std::default_delete<_Ty>>> &)': attempting to reference a deleted function Send File To Server C:\Users\rengland\Workspace_CPP\Library\Includes\boost\asio\basic_stream_socket.hpp 729 

I'm assuming that it's complaining because the code thinks I'm trying to copy the std::unique_ptr, despite my intent being to move it into the callback function. Is there anything I can do to fix this issue, or should I just resign myself to using the std::shared_ptr version?

Xirema
  • 19,889
  • 4
  • 32
  • 68
  • is c++14 an option? You can move a unique_ptr into a lambda, though the syntax to do so wasn't available till c++14 (I believe) – kmdreko May 13 '16 at 17:42
  • @vu1p3n0x I'm using Visual Studio 2015, so it should be c++14 compatible. I'm not sure how that gets around the issue though; is `move`ing into a lambda semantically different than `move`ing into a binder? – Xirema May 13 '16 at 17:44
  • try to make `write` take the unique pointer by reference – kmdreko May 13 '16 at 17:46
  • @vu1p3n0x In what way? by using `std::ref`, or simply feeding it a reference? Because the latter will fail when the `std::unique_ptr` goes out of scope at the end of the function. – Xirema May 13 '16 at 17:48
  • No, `void write(..., std::unique_ptr& write_buffer)` leave the move – kmdreko May 13 '16 at 17:52
  • @vu1p3n0x That worked for the (relatively simple) tests I performed, but does it guarantee that `write_buffer` doesn't get deleted when `write_to_connection` exits? – Xirema May 13 '16 at 17:57
  • yes, the pointer is moved into what `std::bind` returns. And the function is called with the stored pointer. – kmdreko May 13 '16 at 18:00
  • 1
    Imagining that using a unique_ptr over a shared_ptr will increase performance is a false premise. The buffering and network transmissions will consume tens of orders of magnitude more time. – Richard Hodges May 13 '16 at 22:24
  • @richardhodges good to know. – Xirema May 13 '16 at 22:40

0 Answers0