C ++ 11在Lambda中捕获成员变量

时间:2012-12-25 15:38:57

标签: c++ c++11

我有一个成员变量定义为:

HWND WindowHandle。

我正在尝试捕获变量并在Lambda中分配它。所以编译器给了我一个警告,并建议我捕获“这个”。我做了,但现在Handle只在Lambda中有效:S换句话说,它在Lambda之外是NULL。

class Foo
{
    private:
        HWND WindowHandle;

    public:
        Foo();
        void MakeWindow(.......);
        HWND GetWindowHandle() {return WindowHandle;};
};

Foo::Foo(){}

Foo::MakeWindow(.......)
{
    Thread = std::thread([ClassName, Title, Width, Height, this]{
                    WindowHandle = CreateWindowEx(0, ClassName.c_str(), Title.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, 0, 0, GetModuleHandle(NULL), 0);
                    if(WindowHandle)
                    {
                        ShowWindow(WindowHandle, SW_SHOWDEFAULT);
                        MSG msg;
                        while(GetMessage(&msg, 0, 0, 0))
                            DispatchMessage(&msg);
                    }
                });
}


int main()
{
    Foo F;
    F.MakeWindow(........);
    std::cout<<std::boolalpha<<(F.GetWindowHandle() == NULL);  //writes true.
}

以上创建窗口完美!它只是Handle为null。如何从Lambda中获取Handle到我的班级成员?

3 个答案:

答案 0 :(得分:5)

那是因为你的代码有竞争条件。当你检查main()中的值时,线程还没有运行,所以WindowHandle仍然是NULL。

除非你实际上没有启动线程。在这种情况下,由于线程尚未执行,因此WindowHandle仍为NULL。

无论如何,您需要在具有互斥锁的线程之间同步对WindowHandle的访问。

答案 1 :(得分:0)

您只能捕获局部变量,即在创建lambda的函数中声明的内容或其参数之一。在访问成员x时的成员函数中,您实际访问this->xthis是传递给成员函数的对象的隐式指针。因此,lambda将捕获this而不是x。要捕获成员,您需要创建一个包含它的局部变量,然后捕获此变量,例如:

auto&& tmpWindowHandle = this->WindowHandle; // ... or just WindowHandle

...然后你将在lambda函数中捕获tmpWindowHandle

由于你的lambda函数没有显示任何同步,你的GetWindowHandle()似乎也没有任何同步,你的调用线程可能会在你被线程设置之前访问WindowHandle成员:在调用其他线程使用join()之前,您需要某种形式的同步,无论是WindowHandle还是某种形式的互斥或条件变量。整体设置看起来像std::future<...>的良好应用:它旨在可能同时运行一个函数然后阻塞,直到实际访问结果时需要结果。

答案 2 :(得分:0)

您正在不同的主题上分配WindowHandle。所以可能发生的事情是你的新线程还没有开始,你正在检查WindowHandle是否已经改变了。此外,您应该使用某些互斥锁或其他构造来保护对WindowHandle的访问,否则您将遇到竞争条件。