带有unique_ptr捕获的asio lambda

alp*_*pha 5 c++ lambda boost-asio unique-ptr c++11

我正在使用asio独立1.10.6和vs2015 rc.

vs2015支持unique_ptr捕获.所以我写了一些代码如下:

auto data = std::make_unique<std::string>("abc");
auto buffer = asio::buffer(data->c_str(), data->size());
asio::async_write(s, buffer, [data = std::move(data)](
  const asio::error_code& error, size_t byte_transferred) mutable {
  do_something(std::move(data), error, byte_transferred);
});
Run Code Online (Sandbox Code Playgroud)

但是当我编译代码时,编译器说:

错误C2280:....试图引用已删除的函数

据我所知,它说我试图复制lambda,因为lambda捕获a std::unique_ptr,所以它是不可复制的.

令我困惑的是为什么asio想要复制lambda而不是移动lambda.

我的代码出了什么问题?如何解决它?

=========================

完整的代码是:

void do_something(std::unique_ptr<std::string> data) { }

void compile_failed() {
  asio::io_service io_service;
  asio::ip::tcp::socket s(io_service);

  auto data = std::make_unique<std::string>("abc");
  auto buffer = asio::buffer(data->c_str(), data->size());

  asio::async_write(s, buffer, [data = std::move(data)](const asio::error_code& error,
    size_t byte_transferred) mutable {
    do_something(std::move(data));
  });
}

template<typename T > struct lambda_evil_wrap {
  mutable T ptr_;
  lambda_evil_wrap(T&& ptr) : ptr_(std::forward< T>(ptr)) {}
  lambda_evil_wrap(lambda_evil_wrap const& other) : ptr_(std::move(other.ptr_)) {}
  lambda_evil_wrap & operator=(lambda_evil_wrap& other) = delete;
};

void compile_success_but_very_danger() {
  asio::io_service io_service;
  asio::ip::tcp::socket s(io_service);

  auto data = std::make_unique<std::string>("abc");
  auto buffer = asio::buffer(data->c_str(), data->size());

  lambda_evil_wrap<std::unique_ptr<std::string>> wrapper(std::move(data));
  asio::async_write(s, buffer, [wrapper](const asio::error_code& error,
    size_t byte_transferred) mutable {
    do_something(std::move(wrapper.ptr_));
  });
}

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

作为代码,如果我将unique_ptr包装到可复制对象,则编译就可以了.但是lambda_evil_wrap :: lambda_evil_wrap(lambda_evil_wrap const&a)真的很糟糕且不安全.我不知道asio作者是否写了一些代码如下:

Handler handler2(handler);
handler(...); // Crash here
Run Code Online (Sandbox Code Playgroud)

Tan*_*ury 7

原始代码中的错误是处理程序无法满足Handler类型要求,因为它不是CopyConstructible:

处理程序必须满足CopyConstructible类型的要求(C++ Std,20.1.3).

正如Boost.Asio的C++ 11对可移动处理程序的支持所述,在可能的情况下,Boost.Asio将优先于复制构造函数的移动构造函数,但处理程序仍必须是可复制构造的:

[...] Boost.Asio的实现将使用处理程序的移动构造函数而不是其复制构造函数.在某些情况下,Boost.Asio可能能够消除对处理程序的复制构造函数的所有调用.但是,处理程序类型仍然需要是可复制构造的.

要解决此问题,可以考虑使用std::shared_ptr而不是std::unique_ptr,使lambda可以复制构造.