Search code examples
c++lambdaconst-char

Lambda: Is capture of const char * from function scope in lambda undefined behaviour


I have a lambda which uses a const char * defined in function scope. The lambda is executed after the function returns.

void function() {
  const char * UNLOCK_RESULT = "unlockResult";
  .. 
  ..
 TestStep::verifyDictionary(test, [UNLOCK_RESULT](TestStep::Dictionary& dict){
    return 1 == dict[UNLOCK_RESULT].toInt();
  });
  ...
}

If I look at the assembly that GCC generates, the actual char array holding the "unlockResult" is statically allocated. But I was wondering if this is guaranteed by the standard as in theory the const char * is of function scope. Is the capture of const char * undefined behaviour or is this allowed by the standard because of some exception around C++ handling of const char * strings.

I know I can change:

             const char * UNLOCK_RESULT="" 
to 
   constexpr const char * UNLOCK_RESULT=""

And then the discussion falls away because I don't even need to capture it, but I am curious about the const char * case.


Solution

  • You are mixing 2 concepts. In function scope is variable UNLOCK_RESULT itself, so if you try to use reference or pointer to the variable then you would get UB. But as you use a value of that variable which is pointer to static data you are totally fine as such pointer is not invalidated after function terminates.

    If your question is if a pointer to string literal is valid after function terminates, then yes it is valid and guaranteed by C++ standard to have static duration:

    Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

    (emphasis is mine)

    Btw it is an old habit to use identifiers for constants with all uppercase as they used to be defined in preprocessor. When you have compile time identifiers for constants uppercase you would hit exactly the same problem this habit tried to minimize.