2015-06-11 3 views
4

Я использую asio standalone 1.10.6 и vs2015 rc.asio lambda with unique_ptr capture

Поддержка 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); 
}); 

Но когда я компиляции кода, компилятор сказал:

ошибка C2280: .... пытается ссылаться на удаленную функцию

Как я понимаю, он сказал, что я пытаюсь скопировать лямбда, и потому, что лямбда захвата std::unique_ptr, так что это noncopyable.

Что меня пугает, почему асио хочет скопировать лямбду, но не переместить лямбду.

Что случилось с моим кодом? Как обходиться?

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

Полный код:

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; 
} 

В коде, если Я завернул unique_ptr в экземпляр объекта, компиляция в порядке. Но lambda_evil_wrap :: lambda_evil_wrap (lambda_evil_wrap const & a) действительно сосать и небезопасно. Я не знаю, если ASIO автор написал некоторый код выглядит следующим образом:

Handler handler2(handler); 
handler(...); // Crash here 
+0

'std :: ref (лямбда)'? – Jarod42

+0

Вы уверены, что это проблема? Компилятор говорит что-нибудь еще? Всегда включайте полный и неотредактированный журнал ошибок в вопросе. –

+0

Конечно, std :: ref (лямбда) может сделать компилятор счастливым. Но код неправильный. Когда функция вернется, данные будут освобождены и сбой в do_something. – alpha

ответ

4

Ошибка в исходном коде, что обработчик не удовлетворяет Handler type requirement, как это не CopyConstructible:

Обработчик должен соответствуют требованиям типа CopyConstructible (C++ Std, 20.1.3).

Как отмечалось в поддержку Boost.Asio в C++ 11 для movable handlers, где это возможно, Boost.Asio предпочтет конструктор Подвинься конструктор копирования, но обработчик должен еще быть скопировать конструктивны:

[...] Реализация Boost.Asio будет использовать конструктор перемещения обработчика, предпочитая его конструктор копирования. В определенных обстоятельствах Boost.Asio может устранить все вызовы конструктора копии обработчика. Тем не менее, типы обработчиков по-прежнему необходимы для создания копии.

Чтобы решить эту проблему, можно рассмотреть вопрос об использовании std::shared_ptr вместо std::unique_ptr, в результате чего лямбда будет копировать конструктивны.

+0

Я знал, что shared_ptr будет работать. Но do_something (...) хочет unique_ptr, и я не могу преобразовать shared_ptr в unique_ptr, даже если shared_ptr <>. Unique() - true. Итак, как это сделать? – alpha

+0

@alpha Можно управлять типом, который требуется API ('std :: unique_ptr '), с возможностью копирования ('std :: shared_ptr >'). Хотя дополнительный уровень косвенности может быть не идеальным, он по-прежнему обеспечивает безопасную семантику. См. [This] (http://coliru.stacked-crooked.com/a/f012b9dbc2fa7e89) для демонстрации. –

+0

Ницца. Я просто прочитал ваш код. Это хорошее решение. Гораздо лучше, чем мой lambda_evil_wrap. – alpha