C++ Weekly - Ep 382 - The Static Initialization Order Fiasco and C++20's constinit
HTML-код
- Опубликовано: 25 июн 2023
- ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
Upcoming Workshop: Understanding Object Lifetime, C++ On Sea, July 2, 2024
► cpponsea.uk/2024/sessions/und...
Upcoming Workshop: C++ Best Practices, NDC TechTown, Sept 9-10, 2024
► ndctechtown.com/workshops/c-b...
Upcoming Workshop: Applied constexpr: The Power of Compile-Time Resources, C++ Under The Sea, October 10, 2024
► cppunderthesea.nl/workshops/
Discussion: github.com/lefticus/cpp_weekl...
T-SHIRTS AVAILABLE!
► The best C++ T-Shirts anywhere! my-store-d16a2f.creator-sprin...
WANT MORE JASON?
► My Training Classes: emptycrate.com/training.html
► Follow me on twitter: / lefticus
SUPPORT THE CHANNEL
► Patreon: / lefticus
► Github Sponsors: github.com/sponsors/lefticus
► Paypal Donation: www.paypal.com/donate/?hosted...
GET INVOLVED
► Video Idea List: github.com/lefticus/cpp_weekl...
JASON'S BOOKS
► C++23 Best Practices
Leanpub Ebook: leanpub.com/cpp23_best_practi...
► C++ Best Practices
Amazon Paperback: amzn.to/3wpAU3Z
Leanpub Ebook: leanpub.com/cppbestpractices
JASON'S PUZZLE BOOKS
► Object Lifetime Puzzlers Book 1
Amazon Paperback: amzn.to/3g6Ervj
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Object Lifetime Puzzlers Book 2
Amazon Paperback: amzn.to/3whdUDU
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Object Lifetime Puzzlers Book 3
Leanpub Ebook: leanpub.com/objectlifetimepuz...
► Copy and Reference Puzzlers Book 1
Amazon Paperback: amzn.to/3g7ZVb9
Leanpub Ebook: leanpub.com/copyandreferencep...
► Copy and Reference Puzzlers Book 2
Amazon Paperback: amzn.to/3X1LOIx
Leanpub Ebook: leanpub.com/copyandreferencep...
► Copy and Reference Puzzlers Book 3
Leanpub Ebook: leanpub.com/copyandreferencep...
► OpCode Puzzlers Book 1
Amazon Paperback: amzn.to/3KCNJg6
Leanpub Ebook: leanpub.com/opcodepuzzlers_book1
RECOMMENDED BOOKS
► Bjarne Stroustrup's A Tour of C++ (now with C++20/23!): amzn.to/3X4Wypr
AWESOME PROJECTS
► The C++ Starter Project - Gets you started with Best Practices Quickly - github.com/cpp-best-practices...
► C++ Best Practices Forkable Coding Standards - github.com/cpp-best-practices...
O'Reilly VIDEOS
► Inheritance and Polymorphism in C++ - www.oreilly.com/library/view/...
► Learning C++ Best Practices - www.oreilly.com/library/view/... Наука
This is cool. I didn't know that CE had a project mode. Can you share projects that way? It'd certainly be a neat way to share larger examples.
Can share the same as any other link, yeah.
I believe it is worth to mention that the initialization of inline variables (C++17) are partially ordered, they can depend on each other which makes them viable to implement global services (e.g. allocators, debug helpers).
Another great video Jason!
Nice Video. And that CE mode seems useful
I'm glad I've never had to worry about this sort of circumstance..
Also, I would say you could easily have gone with a small font size in CE. Would make it a little easier to read the cramped windows.
That's why I always use singleton pattern in case I ever need a global object at all, so it is constructed on the first call and not before main. If I need early init I just can call it from somewhere early in the program. Of course this also means additional mutex and/or atomic access, but everything has a price and global objects should be avoided anyway.
Is there a way to request constinit'ness in consumer?
Like if provider was in a third party library and I need to know if I can use this library objects safely, e.g. in code executed when my shared library is loaded?
Interesting portable way especially if it resolves heirarchical dependencies. I have been using the constructor attribute for years to control global construction/init sequencing in the embedded world, but this is certainly not portable, but it doesn't require the class constructor to be constexpr.
I mean it's nice to have that fixed, but static globals are code smell anyway.
You're absolutely right, but sometimes you get stuck with legacy code that is chock full of mutable global state, and this can at least get you out of a quagmire while you work toward eliminating it one piece at a time. As someone else mentioned, replacing it with a Meyers (Leaky) Singleton pattern can also resolve the SIOF, and while Singleton is still usually a bad idea, it gives you back some control over construction.
We can put such objects in one struct and make that struct object to be global. This guaranties the initialization order of members.
Anyway thanks for this episode. This was useful to know.
What if there are multiple statics which need to be static initialized with constinit ?what will be the order then ?
The order should be automatically resolved correctly. Remember you can only use constexpr variables at compile time and u can't declare but not initialize constexpr variables.
They're initialized at compile time. The compiler will figure out the order.
Ok thanks
I know about Kongsberg in Norway, but never knew there was a Kongsberg in Sweden as well
Kongsberg, formerly spelled Konningsberg (lit. "King's Mountain"), (wikipedia)
Same here. And I'm Swedish.
@@md2perpe I think he mispoke anyway
There is actually a well defined way to ensure the order they are initialized in, define them within the same TU. (e.g. make a globals.cpp)
That would then require a globals.h with tons of `extern`s which IMO is a code smell (global state probably shouldn't ever be a thing anyway)
@@BryceDixonDev no it doesn't, the externs can be anywhere. While eliminating global state is ideal in some cases it provides greater flexibility and cleaner code (with cavets around testing and threading)
Still feel that putting global in function is superior than constinit, but it's nice to have alternative approach
I feel like those are two different options. Personally, if I know the thing *can* be initialized before runtime, I want it to be!
Is the guarantee here that constinit does not modify compiler behavior in any way (i.e. removing them at the end in this case was OK) ? IOW it always serves to *validate* compiler behavior for the case when you have constexpr constructors.
constinit changes nothing. It just provides a guarantee that your assumptions are correct.
How can we link to gtest in this view ? How to update CMake ?
How to add new files in this CMake view ?
Are you saying "constinint" or are my ears broken?
I heard the same
You ask too much of a computer nerd. It's enough that it's clear what he's trying to say.
Same.
Seems like this is only useful in aesotheric and fictional code:
It works if Global A depends on Global B, and B can be constexpr constructed.
If there are more than 2 globals involved? Supposedly magic happens.
If any of the depended-on globals does not have a constexpr-constructor? Doesn't work.
"constinit" seems to try to work on too many problems and fails to plug many of the holes. It really only should be used for marking variables that need to be const-initialised... and even at that it is not good cause that can and will still happen at runtime - the only guarantee the language really makes is that it it evaluated before all dynamic initialisation - aka before main is called - but it says absolutely nothing about whether it is done at compiletime or not (just most compilers try to do it at compiletime when they can resolve it)
It just provides a compile-time guarantee that you didn't have previously.
I will also hate anybody that overloads &. It's just so unexpected even if you know about the possibilities...
Not sure if anyone's mentioned it, but your audios volume is low in this and other videos of yours :)
Thanks, I just recently tweaked my process. The coming up videos should have better levels.
0:31 Norway 😂
Why do you say that constinit does nothing to the "meaning" of the code when it avoids the implementation-defined behavior of static initialization? constinit changes the output of the compiler because now initializing provider first does not depend on the order of the translation units, so the meaning has changed (at least one could say the semantics or meaning has changed in the case of the incorrect order of translation units).
No, constinit does *not* change the output of the compiler. All it does is ensure that your assumptions are correct. Static initialization rules are required by the standard.
if you have an example that proves me wrong, please open a new issue: github.com/lefticus/cpp_weekly/issues so I can do a follow up episode
@@cppweekly constinit merely requires constexpr, which changes meaning. Your example works to show the point, but it adds both specifiers at the same time.
without constinit, provider before consumer leads to output:
clang++ provider.cpp consumer.cpp main.cpp -std=c++20
"Hello there World!?"
without constinit, consumer before provider leads to no output:
clang++ consumer.cpp provider.cpp main.cpp -std=c++20
""
with constinit, consumer before provider leads to output:
clang++ consumer.cpp provider.cpp main.cpp -std=c++20
"Hello there World!?"
The last two points emit different binaries, and the only difference is the constinit on Provider and thus the constexpr on its ctor. Inspecting further, only the constexpr is required to get "consumer before provider" to give output, so this is the actual semantic change to the meaning of the code.
Oof. I normally prefer the Myers Leaky Singleton pattern. But that's for things like loggers or root exception handlers for poll() based multithreaded code. You know that it won't exist until you call it and that it will never invoke a destructor.
I would argue that if you are encountering these race conditions or thinking about how they work, then you could use refactoring instead.
If you use global statics, you have to worry about this. If you have interactions between static and thread_local, you have to worry about this.
@@cppweekly yeah, but then you also have to resolve it all somehow. Probably by refactoring out of the race-conditions to start.
Woot, the Swedes have invaded Kongsberg?!
Nice. You say "two statics which depend on each other", but neither of them is declared as static...
Global variables have static storage duration in C++. Same goes for variables marked with extern.
@@sledgex9 yes,, I know that, but it may not have been so clear for everyone
Absolutely only a gimmick, I really dont see any real world value. Focus on the core basics and make them really well