Why is nullptr unsafe?
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! ]