7

Section 16.4 of C++ FAQs (2nd Edition) (Paperback) by Marshall P. Cline, Greg Lomow says that inline functions cannot access static data members safely because the function could be called before the static data member is initialized.

I fail to see why this applies to inline functions and not just any functions in other translation units which call a static data member in another translation unit? I fail to see what part "inline" plays in this disaster?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
user997112
  • 29,025
  • 43
  • 182
  • 361
  • I never thought about it before, but yeah, that is a problem isnt it? – Mooing Duck Mar 05 '13 at 21:36
  • Usually the "C++ FAQ" refers to [this](http://http://www.parashift.com), but [16.4 on that site has nothing to do with inline or static](http://www.parashift.com/c++-faq/new-vs-malloc.html), so I'm not sure in this case. I can't find this issue mentioned on the site I linked at all. – Mooing Duck Mar 05 '13 at 21:47
  • @MooingDuck I'm looking at the online PDF copy of the book... – user997112 Mar 05 '13 at 21:49
  • @MooingDuck "C++ FAQs" by Cline – user997112 Mar 05 '13 at 21:57

1 Answers1

7

static variables are fully initialized before any function in that same translation unit (cpp file more or less) is executed. They are not guaranteed to be initialized before main is called if main is in a different translation unit. inline functions are duplicated, where each translation unit has it's own copy. That means that inline functions in different translation units than the static variable might attempt to read/write to that variable before it is properly initialized, resulting in undefined behavior. (The rules are very complicated, but that's what I recall)

§ 3.6.2/4 It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.

and

§ 3.2/3 An inline function shall be defined in every translation unit in which it is odr-used.

inline functions are not really any more dangerous than non-inline functions as far as I know. Any function accessing a static in a different TU is risky, and since inline just happens to put functions in every TU, most of them aren't safe. One workaround is to use the "construct on first use idiom".

Implicit template specializations are complicated, but for completeness:

§ 14.7.1/3 [temp.inst] the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

So static members of template classes are always initialized before use.

All of the above is subject to the the static initialization order fiasco), which the aformentioned "construct on first use idom" solves.

Community
  • 1
  • 1
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • I am afraid this is not true statement: static variables are initialized before any function in that same translation unit (cpp file more or less) is executed. – Slava Mar 05 '13 at 21:44
  • @Slava: in case you meant dynamic vs constant static initialization I clarified that sentence slightly. – Mooing Duck Mar 05 '13 at 21:48
  • But why is this so bad for inline functions, as opposed to functions in general? Surely I could call a static data member from another translation unit, from a non-inline function? (If someone has an answer could they put it as an answer- not a comment and i'll accept) – user997112 Mar 05 '13 at 21:51
  • Yes. The statics may or may not have their initialization deferred. If it is deferred, an inline function might access it before the full initialization takes place. – Mooing Duck Mar 05 '13 at 21:51
  • Ok, if it is not deferred, then that can happen from any other function. Is that the real reason? – Slava Mar 05 '13 at 21:53
  • 2
    @user997112: This is bad for inline functions because an inline function will not force the variable to be initialized before it's used. Normal functions dealing with a static are usually defined in the same TU, and so are usually safe. Normal functions in seperate TUs will have the same issue as inlined functions. – Mooing Duck Mar 05 '13 at 21:54
  • @Slava: If initialization is not-deferred, then it will be initialized before `main`, and all of this is a non-issue. (with the exception of the [static initialization order fiasco](http://stackoverflow.com/questions/5299095/static-initialization-order-fiasco)) – Mooing Duck Mar 05 '13 at 21:55
  • @MooingDuck I see. But then this rule should be: do not access static variable from another translation unit. Why inline functions so special? – Slava Mar 05 '13 at 21:58
  • @Slava: inline functions are special because they are in _every_ translation unit. One of them is safe, and the rest are not. user997112: The "construct on first use idiom" can be used to work around this issue. – Mooing Duck Mar 05 '13 at 22:00
  • @MooingDuck how about template? – Slava Mar 05 '13 at 22:06
  • @Slava: I actually don't know about the rules for static members of template classes, I'll try to look it up. – Mooing Duck Mar 05 '13 at 22:06
  • @MooingDuck +1 for last statement about not more dangerous. I would say this rule is at least questionable. – Slava Mar 05 '13 at 22:09
  • @Slava: Found the bit on templates finally. – Mooing Duck Mar 05 '13 at 22:29
  • @Slava: The entire first portion of my answer was about static members of non-template classes as well as static globals. That part was already covered. No part of his question applies to static function locals. – Mooing Duck Mar 05 '13 at 22:36
  • Anyway I think deferred initialization is mostly related to dynamic loading of shared libraries. This is pretty special case and make this FAQ rule I would say artificial. – Slava Mar 05 '13 at 22:39
  • @Slava: oh probably. The bigger concern to me is the static initialization order fiasco, which this is vaguely related to – Mooing Duck Mar 05 '13 at 22:40