Placing boost socket into std::map

Viewed 634

I was thinking that this would be straight forward but I must be missing something crucial, hence the error =O. I'm receiving the 'use of deleted function' error inside my source file.

Anyhow, I know my header file is correctly hooked up as it's been called properly throughout the source file, besides this line and the source code snippet is the only place that should require evaluation.

Header source code

using boost::asio::ip::tcp;
tcp::acceptor mAcceptor;
std::map<std::string, tcp::socket> mSockets;

Source file code

tcp::socket socket(ioService);
mAcceptor.accept(socket);
std::string myKey = "Socket"; // Didn't add actual key string creation
mSockets[myKey] = socket;

Error

error: Use of delete function 'boost::asio::basic_stream_socket& boost::asio::basic_stream_socket::operator{const boost::asio::basic_stream_socket&)' mSockets[myKey] = socket;

Goes on to say: Is implicitly declared as deleted because 'boost::asio::basic_stream_socket' declares a move constructor or move assignment operator class basic_stream_socket.

Update

@Radosław Cybulski suggested to try std::move(socket) and this eliminated a good portion of the error but this now results in.

Error #2

'boost::asio::basic_stream_socket::basic_stream_socket()' second(std::forward<_Args2>(std::get<_Indexes2>(_tuple2))...)

3 Answers

Try:

mSockets.insert({ myKey, std::move(socket) });

Copy operator is deleted, because there's no good way to copy socket. I mean, you connect to something, then copy and what now? You can send on both copies, only one (which one?), something else? So it's deleted and if you want to pass it around, use move constructor / assignment and std::move.

EDIT: since empty constructor is also deleted, you can't use mSockets[key] = .... So we've to rely on insert / emplace. Why? operator[] on map requires existence of default constructor of value type. I've no idea, why, but here is it.

You cannot use map with boost::asio::ip::tcp::socket as value, because map requires its value to be default constructible (for example default constructed instance is created when map::operator[] is called), asio::ip::tcp::socket doesn't fulfill it because its ctor reqiures at least to take io_context object as argument.

Use shared_ptr or unique_ptr as value of map.

The socket can't be default constructed and the operator you are using requires it to be just that (when the default allocator is used).

T& std::map::operator[](const Key& key):

[...] value_type must be EmplaceConstructible from
std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>(). When the default allocator is used, this means that key_type must be CopyConstructible and mapped_type must be DefaultConstructible.

You can however use emplace() and move the socket into the std::pair<std::string, tcp::socket> that's being emplace constructed:

auto [it, inserted] = mSockets.emplace(myKey, std::move(socket));

This will move-construct the socket using the constructor tcp::socket(tcp::socket&&) instead of tcp::socket() (which doesn't exist as you've noticed).

Related