Why can't lambda (capture of 'this') in a handler function of a member's try-block function get access to private data in VC ++ 2013?

Not the one that might be related to this question about static initializers .

Here the first two functions compile fine, and the last one is not in vC ++, but in clang and gcc:

class A { protected: std::string protected_member = "yay"; public: void withNormalBlock(); void withFunctionBlock(); void noLambda(); }; void A::withNormalBlock() { try { throw std::exception(); } catch (...) { [this]() { std::cout << protected_member << std::endl; }(); } } void A::noLambda() try { throw std::exception(); } catch (...) { std::cout << protected_member << std::endl; } void A::withFunctionBlock() try { throw std::exception(); } catch (...) { [this]() { // this line is the problem: std::cout << protected_member << std::endl; }(); } 

I cannot find anything in the standard to suggest that the handler / catch block of the try function block should be freed from scope or that the lambda closure type should change. The code compiles if the access type is changed to all public ones.

What could be the main reason? Is this a bug, or is it something specific to compiler options that can be changed?

+5
source share
2 answers

This seems to be a bug, and lambda in the catch scope is generated outside the class. I tried to prove that with types, but the Visual Studio lambda names are strangely crippled, and the name itself proves nothing. However, the error codes generated by the following snippet show that the names are different:

 #include <iostream> #include <typeinfo> class Foo { private: public: void testLambda() try { auto tryScope = [this]() {}; void (*p)() = tryScope; } catch(...) { auto catchScope = [this]() {}; void (*p)() = catchScope; } }; 

Error output:

(10): error C2440: 'initializing' : cannot convert from 'Foo::testLambda::<lambda_8a3a8afea7359de4568df0e75ead2a56>' to 'void (__cdecl *)(void)' (15): error C2440: 'initializing' : cannot convert from '<lambda_8cbc08e7748553fb5ae4e39184491e92>' to 'void (__cdecl *)(void)'

+2
source

I would suggest that this is a compiler error. It reports the same error in VS2015. Curiously, an attempt to explicitly mimic the functionality of lambda works without any problems in VS2015

 class A { protected: std::string protected_member = "yay"; public: void withFunctionBlock(); }; void A::withFunctionBlock() try { throw std::exception(); } catch (...) { struct Closure { Closure(A *this_) : this_(this_) {} void operator ()() const { std::cout << this_->protected_member << std::endl; } A *this_; }; Closure(this)(); } 

Interestingly, the VS C ++ compiler does differently under the hood ...

+3
source

All Articles