Hello and welcome to C++ weekly.
I'm your host, Jason Turner.
I'm available for code reviews, contracting,
and on-site training.
In this episode, I want to mention a feature from C++ 17
that, I think, maybe hasn't been given enough attention.
But I want to mention what it is,
why it is there, and maybe perhaps some of the downfall
in using it.
So I'm going to start with a simple struct here.
I've already got it typed out.
This is my struct S. It contains a const static standard string.
And it is equal to the value, hello world.
And as you can see, I get this in class initialization
of static data member S of non-literal type, blah, blah,
blah, compile time error.
This is GCC trunk C++ 17 mode.
You've probably, at some point, wanted to do this.
You've got some data that you know
is constant for the lifetime of the program.
It's const static.
This is a good way to do this.
And then you end up in this world
where you realize you have to do something like this.
You have to give the object.
And you have to give it the correct type and name.
Something like this, you have to give it an initialization
outside of the struct.
Now, the reason for this is you are actually
giving the compiler a place and a time
to initialize the object.
So wherever this is declared is where the object
is going to be initialized.
And it is where its storage will ultimately end up
being handled by the compiler.
And this then gives us some issues
with the static initialization order
fiasco and that kind of thing, which are all terrible.
Now, if you have watched my episode on the cost of using
statics, which is a really, really long time ago that I did
that one, you might be aware of the fact that statics have this
magic static kind of thing that happens in C++ 11.
And that means that they are initialized guaranteed
in a thread safe way.
And we can look at this.
And actually, at the moment, we don't
see any of this thread safe initialization.
That's because, when this line of code right here, line 8,
gets executed, that's when the value is
going to be initialized.
So the compiler doesn't have to actually do anything
to guarantee that this is going to happen in a thread safe way.
That only occurs with the initialize on first use idiom.
And that is when you have a static that is in a function.
It would be awfully handy if we could
put this Hello World up here as we tried to do initially.
And we can't.
We get this compile time error.
But what we can do as of C++ 17 is mark this as an inline const
static variable.
And now it doesn't matter where this struct is defined.
We don't have to actually ever give a CPP file
with a place and a time to initialize
this value S. The compiler handles that magic for us.
And unfortunately, this magic does come with a bit of a cost.
We do now have this check for a guard variable here.
It does have to do a thread safe check and initialization
of this object whenever you go to access it
because the compiler doesn't have any way of knowing who
is going to initialize it when if you have
multiple compilation units.
So that's the downside.
The upside being that this gives us
a handy way of inlining static data.
Now, of course, for something like this, just to be clear,
the zero cost option, that is probably
the one you should consider that does not
have any question about when and where and how the value is
initialized and whether or not there
is a guard value surrounding it would be something like this.
So in this case, we're avoiding the construction
of a standard string.
We are avoiding any static initialization.
We are avoiding the question of any guards or locks
to initialize the value.
And we are taking advantage of string view.
Now, the only non obvious part of this
is that this Hello World right here, being a string literal,
is guaranteed for the life of the program.
This is safe code.
We can safely return this string view from our static member
function.
And it's effectively free.
So this is definitely an aside from the main topic
of this episode but some things to consider
when you're looking at how to make constant global program
wide data and what your options are for them.
And of course, we cannot forget the fact that this can actually
be a constexpr static member function.
And we can use this string view at compile time
if we so needed.
So thank you for watching this episode of C++ weekly.
I hope you enjoyed it.
Be sure to subscribe.