FAQ 16.04 Can inline functions safely access static data members?

FAQ 16.04 Can inline functions safely access static data members?

No!

Static data members should normally be accessed by non-inline functions only (and then only from non-inline functions that are defined in the same source file as the static data member's definition). In some cases inline functions can access static member data, but the programmer needs to think through the issues fairly carefully they're somewhat tricky.

Suppose class Fred contains two static data members: Fred::i_ is of type int and Fred::s_ is of class string, the standard string class. The data member Fred::i_ is initialized before any code starts running, so Fred::i_ can be accessed from an inline function. However if an inline function accesses Fred::s_, and if the inline function is called from another compilation unit, the inline function might access Fred::s_ before it has been initialized (that is, before the constructor of Fred::s_ has run). This would be a disaster.

Static data members are guaranteed to be initialized before the first call to any non-inline function within the same source file as the static data's definition. In the following example, file Fred.cpp defines both static data member Fred::s_ and member function Fred::f(). This means that Fred::s_ will be initialized before Fred::f() is called. But if someone calls inline function Fred::g() before calling Fred::f(), accessing Fred::s_ could be a disaster since Fred::s_ might not be initialized yet.

Here is file Fred.hpp.

 #include <string> #include <iostream> using namespace std; class Fred { public:   static void f() throw();   static string g() throw(); private:   static string s_; }; inline string Fred::g() throw() { cout << s_; return s_; }                           <-- 1 

(1) EVIL: Fred::s_ might not be initialized yet

Here is file Fred.cpp.

 #include "Fred.hpp" string Fred::s_ = "Hello"; void Fred::f() throw() { cout << s_; }                                      <-- 1 

(1) GOOD: Fred::s_ is guaranteed to be initialized

Here is an example showing how the above code could possibly fail (this code is assumed to be in a different source file, such as main.cpp).

 #include "Fred.hpp" int main() { Fred::g(); } 

Note that some but not all compilers will initialize static data member Fred::s_ before main() begins. Thus this code is doubly evil since it will subtly fail on some compilers and accidentally work on others. In fact, its success or failure might even depend on the order that object files are passed to the linker, and some visual environments hide the linker so well that many programmers don't even know the order in which object files are passed to the linker.

To make matters worse, the following source file, say even-worse.cpp, calls inline function Fred::g() therefore accessing Fred::s_ during static initialization. Many compilers will cause this to happen before main() begins, so this is even more likely to cause a problem (but again, the problem will depend randomly on things like the link order, the compiler, the version number, the phase of the moon, etc.).

 #include "Fred.hpp" string x = Fred::g(); 


C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net