gpt4 book ai didi

c++ - 在生命周期有限的多个模块之间共享 std::function

转载 作者:太空宇宙 更新时间:2023-11-04 11:29:39 25 4
gpt4 key购买 nike

我正在一个模块上创建一个 std::function 并将其共享给另一个模块。创建 std::function 的模块具有有限的生命周期,因此当其他模块试图释放 std::function 时,由于该模块已经被释放,所以它无法释放。

// A.dll
// A.h
__declspec(dllexport) void add_handler(std::function<void()> _handler);

// A.cpp
std::function<void()> handler;
void add_handler(std::function<void()> _handler)
{
handler = _handler;
}

// B.dll
void main(void)
{
std::function<void()> handler_tmp = []()
{
// something
};

add_handler(handler_tmp);
}
// B.dll is freed before A.dll

当 B.dll 可能在 A.dll 之前被释放时,我如何在 B.dll 中安全地创建一个 std::function 并与 A.dll 共享它?

最佳答案

这里有几点需要注意。首先,正如您在评论中指出的那样,如果一个对象添加了一个处理程序,它可能应该删除它。因此,关于 RAII 对象,您提出了一个很好的观点。

class B
{
public:
B() { add_handler([](){ /* handler code */ }); }
~B() { add_handler(nullptr); }
};

在您上面的示例中,dll 将在离开 main 时卸载。我知道您上面的代码是一个非常简单的示例,并且是概念性的。尽管如此,此处 lambda 的范围很重要,并且可能会产生一些意想不到的后果。举个例子:

// B.dll
void main(void)
{
{ // <-- providing arbitrary scope for b
B b { };
// [ call other functions on b ]
}

// [ additional code which ends up calling the handler ]
}

如您所知,std::function 只是可调用对象的包装器。在上面的代码(可复制函数对象)中,即使 B 上没有 dtor,代码也会毫无问题地执行处理程序。 'b' 不再在范围内,但 lambda 的拷贝(完整地,包括任何捕获的值和引用)被移动到全局保存的 std::function 中,并且只要全局处理程序就保持有效坚持下去。

跟踪每个赋值,您会看到整个 lambda 正在传递 [R-Value Ref] 并转发和交换。显然,由于此处理程序的实际实现可能会以某种方式对“b”进行操作,因此这是不可取的。但 C++ 的优点之一是不会让您为处理所有这些场景和执行清理的开销付出代价,因此必须小心。

关于c++ - 在生命周期有限的多个模块之间共享 std::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25271531/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com