5

This question (and the code) is inspired by Jason Turner's C++ Weekly episode: Stop Using constexpr (And Use This Instead!)

Assume the code below (compiler explorer)

My understanding is that when declaring a function local variable as static constexpr I am guaranteed that the variable is initialized only once (static), and without any thread safety overhead normally required if the compiler cannot prove single thread access (due to it being constexpr).

But does the c++ standard guarantee this? Is there anywhere in the standard to point to that ensures me that the line static constexpr auto arr = getArr(); will never result in the compiler adding a mutex or other sort of thread protectiong?

Neither Jason Turner's episode, or this stackoverflow question mentions the thread safety overhead that can come with local static variables, and that is the main point I am looking for a definite answer to - preferably by pointing to the standard.

So to be clear: Can I be sure that arr in the getVal() function is initalized at compile time, without the need for any thread synchronization?

constexpr auto getArr()
{
    std::array<int,10> arr;
    for (int i = 0; i < 10; ++i) {
        arr[i] = i*2;
    } 
    return arr;
}

auto getVal(int i)
{
    static constexpr auto arr = getArr();
    return arr[i] + 1;
}

int main()
{
    return getVal(4);
}
cptFracassa
  • 893
  • 4
  • 14
  • `std::array arr;` needs to be initialized to be usable in a constexpr thus `std::array arr{};` And yes C++ since C++11 guarantees threadsafe initialization of static variables at runtime it is by design. See this part of the [C++ standard](https://eel.is/c++draft/stmt.dcl#3) – Pepijn Kramer Jun 10 '23 at 10:54
  • Wording : *If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization* – Pepijn Kramer Jun 10 '23 at 11:00
  • If you use consteval for getArr you will ensure it will only run at compile time. And mutex will not be necessary. – Pepijn Kramer Jun 10 '23 at 11:10
  • @PepijnKramer I know the standard guarantees threadsafe initialization, so my question is really if the combination of static and constexpr mens that it is safety inititialzed at compile time without the need of rustikke checks. – cptFracassa Jun 10 '23 at 11:34
  • Btw, consetval is not an option (yet), we’re still stuck on c++17 for a little time more in the codebase. – cptFracassa Jun 10 '23 at 11:35
  • Ok I finally get what you are saying. It looks to me that you should have a constexpr getVal in that case too (and that cannot have static local variables). Do you mean something like this : https://godbolt.org/z/z764zM9os – Pepijn Kramer Jun 10 '23 at 12:12
  • @PepijnKramer It may be that I explain poorly, but you still don't really get the point I am asking. I am asking whether in normal, (non-constexpr functions), I can now that no thread synchronization will be added if the static variables are consrexpr. – cptFracassa Jun 10 '23 at 13:12
  • It's okay I am really trying to understand (that's why I made an example). Another attempt : https://godbolt.org/z/1c9TzWMzT. I tried on several compilers and all of them put the array in code/data. But my answer must be "I do not know for sure" because I do not know any specific part in the guidelines that say it must be so. – Pepijn Kramer Jun 10 '23 at 14:36

1 Answers1

1

Since the initialization happens at compile time, no synchronization mechanism is needed at runtime. static has no influence on this. It simply makes the value be accessed directly in the data memory segment. Without static the value would have to be copied from there to the stack first.

You won't find a guarantee in the standard that no synchronization mechanism is provided. Implementors are free to add additional code and checks as long as they don't alternate the meaning of your code. But no implementor would add such a mechanism, because it would have no benefit.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • What you write is my understanding as well, `static` is there to avoid copying, but static normally creates the need for thread synchronization. What you say is just that you agree with my understanding, but that's unfortunately little help if I cannot point to anywhere in the standard or anthing else that is concrete. – cptFracassa Jun 10 '23 at 13:15
  • @cptFracassa: The standard isn’t going to say “no mutex is used here” any more than it’s going to say that `std::fmod` doesn’t try to contact Hollywood. An implementation would still be conforming if it did these things, but obviously no one would do so. – Davis Herring Jun 10 '23 at 13:44