From: DeMarcus on
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
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! ]