С ++ идеальная пересылка во вложенной лямбде - PullRequest
0 голосов
/ 17 октября 2018

У меня есть случай, когда я создаю специальный объект потока.Этот объект должен вызывать вызываемый объект так же, как это делает std :: thread, выполнять некоторую проверку, а затем переносить его в другую функцию, которая выполняет некоторые дополнительные действия (точное обоснование является сложным и не имеет отношения к этому вопросу).У меня есть рабочее решение, но я не уверен, что оно оптимально, так как мне не удалось добиться идеальной переадресации.

Я создал следующий пример, чтобы отладить проблему и попытаться понять, в чем заключается моя ошибка.

Пример компилируется и запускается без проблем.Однако средство очистки адресов googletest выдает мне эту ошибку:

AddressSanitizer: стек-использование-за-областью для адреса 0x7ffcea0a8ff0 на ПК 0x00000052a019 BP 0x7fee283febb0 sp 0x7fee283feba8

1010 *1009* 1010есть функция с именем safe_function_executer.В этой безопасной функции внешняя лямбда захватывает функцию и аргументы по значению.У меня также есть функция с именем bad_function_executer, в которой я пытаюсь выполнить идеальную пересылку путем захвата функции и аргументов по ссылке.

Средство очистки адресов Googletest не выдает ошибку для safe_function_executer, но для bad_function_excecuter.

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

#include <atomic>
#include <thread>
#include <array>
#include <functional>
#include <iostream>
#include <chrono>

//!!!WARNING Contrived Example Follows!!!

template<class SomeType, class F, class ...Args>
void a_function_running_function( SomeType& some_arg, F&& f, Args&&... args)
{
    f(std::forward<Args>(args)...);
    *some_arg = 42;
}

template<class SomeType, class F, class ...Args>
std::thread safe_function_executer( SomeType& some_arg, F&& f, Args&&... args )
{
    return std::thread( [=]() mutable { 
        a_function_running_function( some_arg, [&]() mutable {
            f( std::forward<Args>(args)... ); });});

}   


template<class SomeType, class F, class ...Args>
std::thread bad_function_executer( SomeType& some_arg, F&& f, Args&&... args )
{
    return std::thread( [&,some_arg]() mutable { 
        a_function_running_function( some_arg, [&]() mutable {
            f( std::forward<Args>(args)... ); });});

}

void some_function(int arg1, bool arg2, std::tuple<int,bool>& ret)
{
    std::get<0>(ret) = arg1;
    std::get<1>(ret) = arg2;
}

int main()
{
    auto arg = std::make_shared<std::atomic<int>>(0);
    auto ret = std::tuple<int,bool>{0, false};

    //works (but not perfectly forwarded?)
    auto good_thread = safe_function_executer( arg, &some_function,
                                               45, true, ret ); 
    good_thread.join();

    //address sanitizer errors
    auto bad_thread = bad_function_executer( arg, &some_function,
                                             45, true, ret );
    bad_thread.join();
}

1 Ответ

0 голосов
/ 17 октября 2018

Все параметры, которые вы передаете bad_function_executer, являются временными и выходят за рамки основного потока, как только возвращается bad_function_executer.Времена исчезли, но вы все еще используете ссылку на них в своей лямбде в другом потоке.

В вашей хорошей версии вы захватываете args по значению, делая их локальную копию, которая остается вокругчерез время жизни лямбды.

Если вы сделаете их все lvalues ​​и передадите их таким образом, то они останутся в области действия до вызова join (), который позволит вещам работать с bad_function_executer.

int arg1 = 45;
bool arg2 = true;
//address sanitizer errors
auto bad_thread = bad_function_executer( arg, &some_function,
                                         arg1, arg2, ret );

но я думаю, что в этом случае вам лучше просто захватить по значению, как вы делаете с вашей good версией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...