假设我有一个 Window 类,并且该 Window 类具有 std::function 形式的事件处理程序:
struct Event {};
struct Window
{
std::function<void(Event)> handler;
};
Window wnd;
wnd.handler = [] (Event) { /*some fancy handler*/ };
从处理程序内部,我无法访问窗口本身,因此我可以将窗口指针传递给处理程序,也可以通过捕获窗口在处理程序函数内部隐式访问该窗口。然而,在捕获案例中,我认为我遇到了这个问题:
struct Event {};
struct Window
{
std::function<void(Event)> handler;
int member;
};
int main()
{
Window wnd1;
// Capture the window so I can access it inside the handler function
Window wnd2{ [&wnd2](Event) { wnd2.member = 3; } };
wnd1 = std::move(wnd2);
// wnd1 contains a lambda object pointing to wnd2, that's invalid.
Window wnd3 { [&wnd3](int) { wnd3.member = 7; } };
std::vector<Window> wnd_vector{ wnd3 }; // Now when vector reallocates the lambda // object is invalid because of the 'this' pointer, right?
那么我猜的规则是:如果 lambda 对象已捕获外部类(如果外部类是可移动的),则不能拥有包含 lambda 对象的类。我认为这个问题可以扩展到更一般的情况:
struct MoveableClass
{
struct Foo { MoveableClass* outer_class_object; };
Foo fooObj{this};
}
我可以使用自定义移动函数来移动此类。但在 std::function 的情况下或者如果它包含 lambda,那么我无法移动它,对吗?
最佳答案
我向您建议这样的解决方案:
#include <iostream>
#include <vector>
#include <functional>
struct Event {};
struct Window
{
public:
Window() = default;
Window(std::function<void(Window &, Event)> handler)
: handler(handler)
{}
Window(std::function<void(Window &, Event)> handler,
int member)
: handler(handler),
member(member)
{}
void setHandler(std::function<void(Window &, Event)> newHandler)
{
handler = newHandler;
}
bool callHandler(Event event)
{
if (handler)
{
handler(*this, event);
return true;
}
return false;
}
void setMember(int newMember)
{
member = newMember;
}
int getMember() const
{
return member;
}
private:
std::function<void(Window &, Event)> handler; // if it is not needed to change class members than you can use "const Window &"
int member = 0;
};
void print(const Window & obj)
{
std::cout << "Object: " << static_cast<const void *>(&obj) << ", member: " << obj.getMember() << std::endl;
}
int main()
{
Event event;
bool callResult = false;
Window wnd1;
Window wnd2{ [](Window & obj, Event) { obj.setMember(3); } };
callResult = wnd2.callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd2);
wnd2.setHandler( [](Window & obj, Event) { obj.setMember(1); } );
wnd1 = std::move(wnd2);
callResult = wnd1.callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd1);
Window wnd3 { [](Window & obj, Event) { obj.setMember(7); } };
std::vector<Window> wnd_vector{ wnd3 };
callResult = wnd_vector.front().callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd_vector.front());
print(wnd3);
return 0;
}
结果:
Call result: true
Object: 0x7ffd57d9ccb0, member: 3
Call result: true
Object: 0x7ffd57d9cc80, member: 1
Call result: true
Object: 0x2263c30, member: 7
Object: 0x7ffd57d9cce0, member: 0
关于c++ - 一个类是否可以包含一个捕获其所在类的 lambda 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69235611/