首页 > 解决方案 > 在 C++ 中使用函数装饰器(使用闭包)时出现意外的分段错误

问题描述

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

然而,如果我将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;
}

标签: c++lambdaclosuresdecorator

解决方案


不同的是,当你通过值传递函数时,传入 lambda 的参数是对函数参数的引用,返回时超出范围decorator。当您稍后调用返回的 lambda 时,您会引用这个超出范围的变量,即未定义的行为。

它在您通过通用引用传递时起作用,传递给的参数decorator是一个引用,它被传递给 lambda。所以以后调用 lambda 时它仍然有效。

您可以将 lambda 更改为按值传递(使用[=])以使更改后的版本正常工作。


推荐阅读