2012-12-25 33 views
3

我有一个成员变量定义为:C++ 11 Capture成员变量在Lambda中

HWND WindowHandle。

我想捕获变量并在Lambda中赋值给它。所以编译器给了我一个警告,并建议我捕获“this”。我做了,但现在句柄只在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. 
} 

以上创建的窗口非常好!这只是句柄为空。我怎样才能从Lambda内的句柄到我的班级成员?

回答

5

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

除非你还没有真正开始线程。在那种情况下,由于线程没有执行,WindowHandle仍然是NULL。

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

+0

你是对的!我只是放了一个大的睡眠,事实证明它不是NULL。现在我必须深入Mutexes:l – Brandon

+4

@CantChooseUsernames实际上,尽管互斥锁可以解决这个问题,但清理代码设计可能是一个更好的主意:在正常情况下,外部世界不应该要求诸如窗口句柄之类的信息。隔离依赖关系并且不向外部世界提供内部。当其他代码想要从窗口中获取某些内容时,让他们调用'Foo'上的方法而不是暴露窗口句柄。 –

+1

@CantChooseUsernames互斥量非常容易,特别是当您使用RAII互斥锁时,比如'std :: lock_guard'(http://en.cppreference.com/w/cpp/thread/lock_guard),这有助于避免一些非常常见的导致死锁的新手错误。 –

0

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

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

...然后你会在你的lambda函数捕获tmpWindowHandle

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

+0

这是不正确的。你可以在一个lambda中捕获'this',并访问lambda定义的对象的每个成员。 –

+0

@Ravadre这是一半正确的。当你捕获这个'',你没有捕获所有的成员。你只捕获'this',一个单一的对象指针。 –

+0

@NikosC .:请阅读我的回复,并告诉我在哪里我声称你*无法捕捉这个!事实上,我甚至说,不是成员变量'this'被捕获。 ......并且你*无法捕获成员变量是绝对正确的。 –

0

您正在分配不同线程上的WindowHandle。因此,可能发生的情况是您的新线程尚未开始,并且您正在检查WindowHandle是否已经更改。此外,你应该保护与某些互斥或其他构造的访问WindowHandle,否则你将有一个竞争条件。