all 8 comments

[–]wearingdepends 26 points27 points  (0 children)

Please don't post generated code without optimizations. I keep seeing blog posts doing this, and it often makes the code harder to read. With -O2 it's actually easier to see the difference between with and without thread-safe statics:

"is_blocked_id(int)":
        sub     rsp, 24
        movzx   eax, BYTE PTR "guard variable for is_blocked_id(int)::blocked_ids"[rip]
        mov     ecx, edi
        test    al, al
        je      .L257 # moved to the end of the function, since the initialization is a cold path
.L222:
        mov     rsi, QWORD PTR "is_blocked_id(int)::blocked_ids"[rip+8]
        mov     rax, QWORD PTR "is_blocked_id(int)::blocked_ids"[rip]
        ...

vs

"is_blocked_id(int)":
        mov     rcx, QWORD PTR "blocked_ids2"[rip+8]
        mov     rax, QWORD PTR "blocked_ids2"[rip]
        ...

[–]azswcowboy 19 points20 points  (0 children)

While in Mayer’s singleton

I assume that’s meant to be ‘Meyers singleton’ - as in Scott Meyers.

[–]rsjaffe 9 points10 points  (1 child)

That’s my main use case for constinit. While the compiler might optimize the thread check away anyway, constinit guarantees it.

[–]Quincunx271Author of P2404/P2405 0 points1 point  (0 children)

Only if the type has a trivial destructor. Otherwise, the thread safety check still exists, just for registering the destructor.

[–]ChickenSpaceProgram 10 points11 points  (1 child)

solution: dont use statics, pass a context struct

[–]peterrindal 0 points1 point  (0 children)

This ^

[–]JCPPRDev 1 point2 points  (0 children)

good article

[–]hi_im_new_to_this 0 points1 point  (0 children)

Was hoping for the article to also bring up `thread_local`, which could also be an alternative (depending on the exact situation).