Prev: linktime error for function overloads in template class when library is a dynamic library
Next: Bitwise copy contructor
From: DeMarcus on 19 Mar 2010 16:13 Hi, I implemented the nullptr workaround found here in Section 1.1. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf However, I get some nasty behavior when initializing static variables. Here is the code. // From N2431, Section 1.1. const class { public: template<class T> operator T*() const { return 0; } template<class C, class T> operator T C::*() const { return 0; } private: void operator&() const; } nullptr = {}; // My test (in the same file). #include <iostream> #include <assert.h> template<typename T> class StaticInit { public: static T& value() { std::cerr << "value() - " << "Initialied: " << initialized_ << " Pointer: " << pointer_ << std::endl; if( initialized_ == false ) { pointer_ = new T; initialized_ = true; } assert( pointer_ ); return *pointer_; } private: static T* pointer_; static bool initialized_; }; template<typename T> T* StaticInit<T>::pointer_ = nullptr; template<typename T> bool StaticInit<T>::initialized_ = false; typedef StaticInit<int> SIInt; struct SomeClass { SomeClass() { SIInt::value() = 47; } } someClass; // NOTE! Static variable calling SIInit. struct SomeClass2 { SomeClass2() { SIInt::value() = 11; } } someClass2; // NOTE! Static variable calling SIInit. int main() { std::cerr << SIInt::value() << std::endl; } When I run this program I get two initializations of pointer_. First I get the mandatory zero-initialization [�3.6.2/2]. Then I get pointer_ initialized when SIInt::value() is called from SomeClass. After that I get pointer_ initialized again with nullptr! This was compiled with gcc 4.4.1. To see the effect even more clear, substitute nullptr's return 0; with return (T*)8; You may refer to "The static initialization order fiasco" (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12), but why? In order to have only one initialization, nullptr must be a const expression, right? Maybe that's my question; what is a const expression, or when can I be sure to avoid late initialization with the nullptr workaround (or any other initializer for that matter)? I tried to understand [�5.9/2] (from the N2798 draft). Is nullptr not a constant expression because I use "a class member access unless its postfix-expression is of effective literal type or of pointer to effective literal type"? Am I discouraged to use the nullptr workaround, and instead use NULL until we get the real nullptr? Would it be better if I just did a #define nullptr 0 for now? Thanks, Daniel -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: DeMarcus on 20 Mar 2010 04:18
DeMarcus wrote: > Hi, > > I implemented the nullptr workaround found here in Section 1.1. > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf > > However, I get some nasty behavior when initializing static variables. > Here is the code. > > // From N2431, Section 1.1. > const > class > { > public: > template<class T> > operator T*() const { return 0; } > > template<class C, class T> > operator T C::*() const { return 0; } > > private: > void operator&() const; > > } nullptr = {}; > > > // My test (in the same file). > > #include <iostream> > #include <assert.h> > > template<typename T> > class StaticInit > { > public: > static T& value() > { > std::cerr << "value() - " > << "Initialied: " << initialized_ > << " Pointer: " << pointer_ << std::endl; > > if( initialized_ == false ) > { > pointer_ = new T; > initialized_ = true; > } > assert( pointer_ ); > return *pointer_; > } > > private: > static T* pointer_; > static bool initialized_; > }; > > template<typename T> > T* StaticInit<T>::pointer_ = nullptr; > > template<typename T> > bool StaticInit<T>::initialized_ = false; > > typedef StaticInit<int> SIInt; > > struct SomeClass > { > SomeClass() { SIInt::value() = 47; } > > } someClass; // NOTE! Static variable calling SIInit. > > struct SomeClass2 > { > SomeClass2() { SIInt::value() = 11; } > > } someClass2; // NOTE! Static variable calling SIInit. > > int main() > { > std::cerr << SIInt::value() << std::endl; > } > > When I run this program I get two initializations of pointer_. First I > get the mandatory zero-initialization [�3.6.2/2]. Then I get pointer_ > initialized when SIInt::value() is called from SomeClass. After that I > get pointer_ initialized again with nullptr! > I think I found the answer myself. For those interested in this issue I found the N2235 Generalized Constant Expression document. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf Read Section 3.4 Unexpected dynamic initialization. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |