0

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.

Andrew Goedhart
  • 937
  • 9
  • 17
  • Tested difference between optimization levels O2 and O0? Whether `const char*` points to a fixed array or something unknown at compile time? – ALX23z Nov 21 '19 at 20:09
  • @ALX23z I hardly doubt you can ever determine if program has UB or not by testing or looking into assembly, you need to know that. – Slava Nov 21 '19 at 20:37
  • @SlavasupportsMonica - this question has nothing to do with UB. OP was confused with the implemented method the compiler used for capturing the const char pointer. – ALX23z Nov 21 '19 at 20:42
  • @ALX23z I believe it is with UB as OP asks if `const char *` would be still valid after function exits, and having it invalid is exactly UB and I doubt you can test that. – Slava Nov 21 '19 at 20:49
  • @ALX23z actually SlavassupportMonica is right. The issue was about the storage duration of the memory pointed to by the captured const char * not the pointer itself. If the memory pointed had function scope then we would have UB but as multiple people have been kind enough to point out, a string literal has static scope so no UB – Andrew Goedhart Nov 21 '19 at 20:50
  • @SlavasupportsMonica this is why I ask about tests for. Whether it was tested in environment without optimizations and in cases where compiler is unaware of actual usage of the lambda. If the whole lambda was optimized and utilized in a scope then compiler could optimize the usage of the lambda and `const char*` - which could result is a static allocation. – ALX23z Nov 21 '19 at 21:06

2 Answers2

2

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.

Slava
  • 43,454
  • 1
  • 47
  • 90
2

The behavior is well-defined.

The lambda [UNLOCK_RESULT](TestStep::Dictionary& dict){...} captures the pointer by-value. So UNLOCK_RESULT inside the lambda is a copy of the original UNLOCK_RESULT, the latter does not have to exist for the duration of the lambda.

Now the string literal "unlockResult" has static storage duration, which means it's allocated at program start and remains available for the duration of the program:

All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program.

rustyx
  • 80,671
  • 25
  • 200
  • 267