I am trying to simplify code in the SFML library ensuring that the first created object of type AudioResource
initializes an audio device, and that the last destroyed object deinitializes it.
As I believe that the current solution using std::shared_ptr
and std::weak_ptr
is overkill, I came up with a simpler alternative using a static
global variable. Here’s a simplified version (the real one is protected by std::mutex
, see PR link above):
// AudioResource.hpp --------------------------------
struct AudioResource
{
AudioResource();
~AudioResource();
// ...
};
// AudioResource.cpp --------------------------------
#include "AudioResource.hpp"
static int deviceRC = 0;
AudioResource() { if (deviceRC++ == 0) { /* init device */ }; }
~AudioResource() { if (--deviceRC == 0) { /* deinit device */ }; }
// ...
I’m quite sure that the code above is fine and not subject to static order initialization fiasco, as the deviceRC
global static
variable is defined only in AudioResource.cpp
and only accessed in that same TU.
My understanding is that, as long as there are no dependencies between multiple global static
variables from different TUs, there’s no risk here whatsoever.
Is my understanding correct, or is it possible that the code above results in undefined behavior by accessing an uninitialized deviceRC
somehow?
Is it possible that there is some weird scenario where creating AudioResource
objects from multiple TUs or when using SFML as a shared library can cause problems with this particular incantation?
Is it correct to say that it’s safe even if deviceRC
does not get constant-initialized?
Other maintainers of SFML have been adamant in suggesting the use of a function-scope static
variable here:
// AudioResource.cpp --------------------------------
#include "AudioResource.hpp"
static int& deviceRC()
{
static int result = 0;
return result;
}
AudioResource() { if (deviceRC()++ == 0) { /* init device */ }; }
~AudioResource() { if (--deviceRC() == 0) { /* deinit device */ }; }
// ...
However, I think that doesn’t make the code any safer nor it is necessary. Am I correct, or is the fuction-scope static
variable here necessary?