在C ++中使用函数装饰器(使用闭包)时发生意外的分段错误

时间:2019-07-08 23:33:37

标签: c++ lambda closures decorator

我创建了decorator函数以将功能添加到现有功能中。程序将输出正确的函数指针地址以及经过的时间以按预期迭代10 x helloworld

但是,如果我更改decorator函数以按值(original_functionFunctionPointer 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 个答案:

答案 0 :(得分:4)

区别在于,当您按值传递函数时,传递给lambda的参数是对函数参数的引用 ,当decorator返回时,该参数将超出范围。以后调用返回的lambda时,将引用此超出范围的变量,即Undefined Behavior。

当您通过通用引用传递时,它起作用,传递给decorator的参数是引用,传递给lambda。因此,稍后调用lambda时仍然有效。

您也许可以将lambda更改为按值传递(使用[=]),以使更改的版本生效。