Неожиданная ошибка сегментации при использовании функции decorator (с использованием замыкания) в c ++ - PullRequest
1 голос
/ 09 июля 2019

Я создал функцию decorator, чтобы добавить функциональность к существующим функциям. Программа выводит правильные адреса указателей на функции, а также истекшее время для итерации 10 x helloworld, как и ожидалось.

Тем не менее, если я изменю функцию decorator на значение original_function по значению (FunctionPointer original_function), программа завершит работу с ошибкой сегментации, которая я не могу понять, почему она не работает.

#include <iostream>
#include <chrono>

typedef void (*FunctionPointer)();

auto
decorator(FunctionPointer && original_function) // if changed to FunctionPointer original_function, it causes segmentation fault when the closure(lambda expression) is called later on
{
    std::cout << "Decorator: " << (void*)original_function << std::endl; // 0x558072fb0b90
    return [&]()
    {
        std::cout << "Decorator: " << (void*)original_function << std::endl; // 0x558072fb0b90 but 0x0 when original_function passed by value
        auto t0 = std::chrono::high_resolution_clock::now();

        original_function();

        auto duration = std::chrono::high_resolution_clock::now() - t0;

        std::cout << "\nElapsed " << duration.count() * 1000.0f << " ms\n";
    };
}


void
helloworld(void)
{
    for (auto i = 0; i < 10; i++)
        std::cout << "Hello, World!\n";
}

int
main(void)
{
    std::cout << "Main: " << (void*)helloworld << std::endl; // 0x558072fb0b90

    auto my_helloworld = decorator(helloworld);
    my_helloworld();

    return 0;
}

1 Ответ

4 голосов
/ 09 июля 2019

Разница в том, что когда вы передаете функцию по значению, переданный в лямбду параметр является ссылкой на параметр функции , который выходит из области видимости при возврате decorator. Когда вы позже вызываете возвращаемую лямбду, вы ссылаетесь на эту переменную вне области видимости, которая является неопределенным поведением.

Работает, когда вы передаете по универсальной ссылке, параметр, переданный в decorator, является ссылкой, которая передается в лямбду. Так что это все еще в силе позже, когда вы называете лямбду.

Вы можете изменить лямбду, чтобы она передавалась по значению (используйте [=]), чтобы заставить работать измененную версию.

...