匿名Lambda会在通话中维护他们的地址吗



我有一些代码,需要在一些函数中创建唯一的id来跟踪一些由该函数操纵的对象。我考虑过使用函数所期望的回调地址。传递给函数的回调是匿名lambda。

我在许多不同的地方调用这个函数,在每个地方,每个lambda都在调用中维护其地址。也就是说,即使lambda是临时的,每次传递给函数时,每个lambda都有相同的地址。

对于我的用例来说,这很好。但是,为什么他们有相同的地址,而不是每次都有一个新的地址?最重要的是,这在编译器之间是否可靠?

编译器:MSVC 2019

// A method within some class.
void Method() {
// Helper lambda
auto makeSignal = [this](State& state, Data& data, int foo, auto&& onClick) {
DoMakeSignal(state, data, true, foo, 3.14, std::forward<decltype(onClick)>(onClick));
};

// The unique-id will be the address of the lambda.
// Everytime this 'Method' is called, this lambda 
// will have the same address. Nice, but why?
makeSignal(GetState(), GetData(), 5, [this] {
log("signal callback");
});
makeSignal(GetState(), GetData(), 42, [this] {
log("signal callback");
});    
}
// In another file
void DoMakeSignal(State& state, Data&, bool, int, float, auto&& onClick) {
uintptr_t uid = reinterpret_cast<uintptr_t>(&onClick);
state.mLastObjectUid = uid;
// ...
}

这纯属偶然。lambda对象只生存到makeSignal调用结束,之后该对象占用的地址可以重用。

无法保证新的lambda对象(或任何其他对象(是否具有相同的地址。

特别地,这也意味着在调用makeSignal之后,如果onClick是通过指针或引用存储的,那么调用它将导致UB,因为对象不再活动。


但是,每个lambda表达式都有自己的类型和自己的调用运算符函数,这两个属性都可以用来获得唯一的id来标识特定的lambda表达式。


如果您想要lambda表达式的唯一id,并且lambda表达式,则例如以下内容应该有效:

struct id_t {};
template<typename> id_t id_var;
template<typename T> constexpr auto id = &id_var<std::remove_cvref_t<T>>;
//...
state.mLastObjectUid = id<decltype(onClick)>; // type: id_t*

相关内容

最新更新