Added comments to clarify static intialization...
...and static de-initialization problems.
This commit is contained in:
parent
f2cc41ebe3
commit
183069699d
2 changed files with 40 additions and 8 deletions
|
@ -24,10 +24,15 @@
|
|||
|
||||
namespace n_token {
|
||||
|
||||
/// Do not inline this enforces static initialization order
|
||||
/// Do not inline this enforces static initialization order and static de-initialization order
|
||||
const t_token & t_token::z_empty() {
|
||||
static t_token z_empty("", false);
|
||||
return z_empty;
|
||||
//This is NOTa memory leak
|
||||
//It is static so it is only allocated once and not de-allocated until the program terminates.
|
||||
///If changed to a static reference it may cause a static de-initialization
|
||||
//core dump when the destructor for z_empty is called here before its last use in another file.
|
||||
//Do not remove the = new t_token("", false);
|
||||
static t_token *z_empty = new t_token("", false);
|
||||
return *z_empty;
|
||||
}
|
||||
}//end namepace
|
||||
|
||||
|
|
|
@ -40,13 +40,35 @@ namespace n_token {
|
|||
It is typically reference counted unless explicitly requested otherwise upon construction (i.e for static strings)
|
||||
|
||||
The copying of tokens is faster than the creation of tokens, because a reference object isn't created.
|
||||
Hence use static tokens as replacements for constant string literals in the code, as follows:
|
||||
static const t_token z_some_string("some_string", false);
|
||||
Hence use static tokens as replacements for constant string literals in the code in a local scope, as follows:
|
||||
static const t_token z_some_string("some_string", false);
|
||||
@see below on caveats in Static Initialization
|
||||
|
||||
@note It is intentionally inconvenient to convert to std::string. Allowing automatic conversion would allow
|
||||
the compiler to create std::string temporaries and give up the benefits of the t_token. Do not
|
||||
make a std::string conversion operator.
|
||||
|
||||
@par @b Static Initialization and Deinitializtion @b
|
||||
Static initialization problems can occur when a static file local variable from one compilation unit/file is
|
||||
accessed in a function called from another compilation unit/file during static initialization/de-initialization.
|
||||
The initialization order is not specified in the C++ spec and hence potentially random. There are 3 ways to fix
|
||||
it for 3 different use cases, outlined below.
|
||||
|
||||
@li 1. Create a non-inlined function that allocates (via new) a static pointer to a t_token and return a reference to it.
|
||||
This is used in z_empty() and is rock solid and never fails. As long as it is not inlined the static allocation is executed once
|
||||
when control passes over the line. It is never de-allocated so it never faces the static de-initialization problem. The downside
|
||||
is that is always results in the overhead of a function call. It is necessary for creating default parameters in function
|
||||
declarations.
|
||||
|
||||
@li 2. Use new to allocate a static pointer in a local scope block. This is also rock solid and works for everything except
|
||||
creaing default parameters in function declarations. This has the slight drawback of the pointer overhead.
|
||||
static t_token *z_empty = new t_token("", false);
|
||||
|
||||
@li 3. Lastly create a static object in a local scope. This is avoids the pointer dereference, but risks a static de-initalization
|
||||
core dump if z_some_string is deallocated before its last use. If you are sure that this function is never called by destructors
|
||||
outside of the compilation unit/file that it is created in, then this method is correct, but a little risky
|
||||
static const t_token z_some_string("some_string", false);
|
||||
|
||||
*/
|
||||
|
||||
class t_token : public n_interned::t_interned_token<std::string> {
|
||||
|
@ -80,9 +102,14 @@ public:
|
|||
|
||||
/// Do not inline this enforces static initialization order
|
||||
template <char T_defval>
|
||||
const t_token& t_token::default_value() {
|
||||
static t_token z_defval(std::string(1, T_defval), false);
|
||||
return z_defval;
|
||||
t_token const & t_token::default_value() {
|
||||
//This is NOTa memory leak
|
||||
//It is static so it is only allocated once and not de-allocated until the program terminates.
|
||||
//If changed to a static reference it may cause a static de-initialization
|
||||
//core dump when the destructor for z_empty is called here before its last use in another file.
|
||||
//Do not remove the = new t_token(std::string(1, T_defval), false); part
|
||||
static t_token *z_defval = new t_token(std::string(1, T_defval), false);
|
||||
return *z_defval;
|
||||
}
|
||||
|
||||
inline std::string operator+(const n_token::t_token &a, const std::string &b) { return static_cast<std::string const &>(a) + b; }
|
||||
|
|
Loading…
Add table
Reference in a new issue