Yup, That’s because in C++ the order of initialisation of static variables is undefined, and var itself has some internal static variables which must have been created before it can be safely used.
So the take-home message is: Don’t use var (or any complex type, really!) in file-scope statics. You’re probably OK with them in function-scoped statics though.
This is known as the static initialisation order fiasco, and stems from initialisation order of static variables between compilation units being undefined. Putting the static at class scope as you have done won’t help because it doesn’t impose any further constraints on initialisation order. What you need to do is place the static inside a function (or method) as @jules suggested, therefore forcing the static to be initialised when the function is first called. This is sometimes called lazy initialisation.
Thanks for the link. I was already trying to further wrap the static in a class, but I hadn’t thought of wrapping it in a function.
My situation is a bit more complicated because I am actually trying to create an std::shared_ptr of type var. I didn’t bring this up in the last post because it didn’t seem relevant then, but it seems relevant now.
The behavior I’m trying to replicate is this:
class SomeClass
{
static const std::shared_ptr<var> m_vars;
}
(Let’s forget about the std::vector for now, although it will be there in my final solution).
Using the Construct on First Use Idiom, I need to use a function to declare the static. Should that function return static const std::make_shared like this?
Or should the function return a std::shared_ptr instead of std::make_shared? I didn’t know about static declarations inside functions until today, so I’m not yet able to picture how they will interact with the reference count inside shared_ptr.
Note: a static std::shared_ptr might seem like a dubious concoction to begin with, but I believe that it makes sense in the context I’m working in. I can elaborate if necessary.
IIRC the method that returns the static instance can itself be static, saving you the need to create a temporary object just to call it, so your code becomes:
class SomeClass
{
public: // you can spare 'public' only if you declare this a struct instead of a class
static const std::vector<var>& getVars()
{
static const std::vector<var> m_vars;
return m_vars;
}
}
@Anima
Yeah, I know it sounds a bit crazy. I suppose it’s good for me to take the time to spell this out in full, so that I can get feedback on whether the whole thing makes sense or not.
Short version: I’m actually not trying to create a static std::shared_ptr, but rather trying to create a static object which has a shared_ptr as an argument. This runs into the same problems as described above, which is why I simplified it a bit in the previous posts.
Long version: I have a functor class CopyPropertiesFromVector that I’m using to copy properties from an std::vector to a ValueTree. Now CopyPropertiesFromVector has a std::shared_ptr to another CopyPropertiesFromVector object, which it can fall back to if this one doesn’t work. The class is working really well, and I want to keep the shared_ptr functionality, as it gives me a lot of flexibility.
But there are some copy profiles that I’m using quite commonly, so I thought I’d make them static. So what I want to create is something like the following pseudo-code:
I think shared_ptr is not what you want in this case. A shared_ptr is a solution to share the ownership of an object between multiple objects or local references, that have an interest.
static variables have an undetermined lifetime, so the lifetime of the object in your shared_ptr gets an undefined lifetime too, which is probably not what you want.
A SharedResourcePointer is basically a singleton, but it is created and destroyed on the fly. Every time you need an object of X just create a SharedResourcePointer and done. If there is already one, you get it. If not it is created. A good use case is the AudioFormatManager. You need it from time to time, but actually you don’t care if it’s there or not. You just don’t want to create it too often. So when your DAW restores a session, it needs it often, so there is a high chance, there is already one present, and it will use it. But later, when all your sounds are in memory, nobody needs it, so in a SharedResourcePointer, it will be removed, vs. a singleton would linger around until the program is closed (or it is manually removed).
A shared_ptr is completely separate from these two, and has a totally different use case:
Two objects have an interest in X. X shall be present, as long as one of the interested ones are alive.
To allow that, the object X has a reference counter, it knows, how many people are looking at it. And if the last one switched off the telly, the object knows, it can go home, nobody is watching any longer.
The shared_ptr is the same like juce’s ReferenceCountedObject with an implementation detail different, intrusive vs. non intrusive reference count, which probably doesn’t matter for you at the moment.