Initialize static members outside the class

S

Steven Woody

Hi,

Supposing a class get a complicated static member foo, and it need to
be initialized before any method of the class can be called, where
should I put these initialization code? I don't want to put them in
main(), it's so far away.

Thanks.

-
narke
 
L

Lionel B

Hi,

Supposing a class get a complicated static member foo, and it need to be
initialized before any method of the class can be called, where should
^^^^^^
I presume you mean non-static method
I put these initialization code? I don't want to put them in main(),
it's so far away.

IIRC, a static class data member will be initialised before entering
main(), so as long as you don't instantiate any class objects before
entering main() you'll be ok*.

Then it depends how you organise your code, really. A common scenario is
that you'd have a class Myclass, say, declared in the header myclass.hpp
and with definitions in the compilation unit myclass.cpp. In which case,
it seems appropriate to define and initialise your static members in
myclass.cpp.

* The only thing to watch out for is the so-called "static initialisation
order fiasco", where you have several static initialisations in different
compilation units, that depend on each other, so that initialisation
order matters... except that the C++ standard doesn't guarantee any
particular compilation order... see:

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
 
S

Steven Woody

^^^^^^
I presume you mean non-static method


IIRC, a static class data member will be initialised before entering
main(), so as long as you don't instantiate any class objects before
entering main() you'll be ok*.

Then it depends how you organise your code, really. A common scenario is
that you'd have a class Myclass, say, declared in the header myclass.hpp
and with definitions in the compilation unit myclass.cpp. In which case,
it seems appropriate to define and initialise your static members in
myclass.cpp.

The question is how to define these initialise. You know, for a
simple member, I can
do something like:
int MyClass::myMember = 123;
but for complicated non-POD types, such as a std::vector, how do I
initialize it by
push_back() many elements into it? You see my problem? Thanks.
 
J

joseph cook

The question is how to define these initialise.  You know, for a
simple member, I can
do something like:
   int MyClass::myMember = 123;
but for complicated non-POD types, such as a std::vector, how do I
initialize it by
push_back() many elements into it?   You see my problem?  Thanks.

Define in one place the same as you would the 'myMember' object.
Initialize in the constructor; that must be called before any methods
of the class.

Of course, you could just add the following:
std::vector<int> NonPOD::foo(SIZE,4.4); // initialize to 4.4

Joe Cook
 
L

Lionel B

The question is how to define these initialise. You know, for a simple
member, I can
do something like:
int MyClass::myMember = 123;
but for complicated non-POD types, such as a std::vector, how do I
initialize it by
push_back() many elements into it? You see my problem? Thanks.

One way is to use a (static, possibly member) function to initialise your
variable:

// foo.hpp

#ifndef FOO_HPP
#define FOO_HPP

#include <vector>

class Foo
{
public:
static std::vector<int> static_member;

static void static_initialiser(const int z);

Foo();

double y;
};

#endif

// foo.cpp

#include "foo.hpp"

#include <iostream>

std::vector<int> Foo::static_member;

void Foo::static_initialiser(const int n)
{
std::cout << "Foo::static_initialiser()" << std::endl;
for (int i=0; i<n; ++i) static_member.push_back(i*i);
}

Foo::Foo()
{
std::cout << "Foo::Foo()" << std::endl;
}

// main.cpp

#include "foo.hpp"

#include <iostream>

int main()
{
const int n = 4;

Foo::static_initialiser(n);

Foo foo;

for (int i=0; i<n; ++i) std::cout << Foo::static_member << '\n';

return 0;
}

// output

Foo::static_initialiser()
Foo::Foo()
0
1
4
9

Note that this won't work if Foo::static_member has to be const. To
handle that situation you can still use a static initialiser function,
but it must return the value you want assigned to your static member.
 
S

Saeed Amrollahi

The question is how to define these initialise.  You know, for a
simple member, I can
do something like:
   int MyClass::myMember = 123;
but for complicated non-POD types, such as a std::vector, how do I
initialize it by
push_back() many elements into it?   You see my problem?  Thanks.






- Show quoted text -- Hide quoted text -

- Show quoted text -

Hi
I frequently encounter the problem and I try to decouple the complex
object from the main class:
// X.h
class X { // wrap the static vector
vector<int> v;
public:
FillVector() { /* your push_back */ }
X() { FillVector(); /* ... */ }
};

// Y.h
class Y { // contains the static object
static X x;
/* other code */
};

// Y.cpp
X Y::x;

I hope it helps.

Regards,
Saeed Amrollahi
 
J

James Kanze

Which can be tricky, since C++ doesn't guarantee the order of
initialization across translation units.

In practice, and modulo dynamic loading. (For obvious reasons,
a object with static lifetime in a dynamic object won't be
initialized before that object is loaded.)
The question is how to define these initialise.

The same way as you would for any element of the type.
You know, for a simple member, I can do something like:
int MyClass::myMember = 123;
but for complicated non-POD types, such as a std::vector, how
do I initialize it by push_back() many elements into it? You
see my problem? Thanks.

Obviously, you can't use push_back, but I still don't see your
problem. What's wrong with:

std::vector< int > const Class::staticVect(
begin( something), end( something) ) ;

Alternatively, you can derive from std::vector, and add whatever
initialization code you want to the constructor of the derived
class.
 
S

Steven Woody

Which can be tricky, since C++ doesn't guarantee the order of
initialization across translation units.


In practice, and modulo dynamic loading. (For obvious reasons,
a object with static lifetime in a dynamic object won't be
initialized before that object is loaded.)


The same way as you would for any element of the type.


Obviously, you can't use push_back, but I still don't see your
problem. What's wrong with:

std::vector< int > const Class::staticVect(
begin( something), end( something) ) ;

Alternatively, you can derive from std::vector, and add whatever
initialization code you want to the constructor of the derived
class.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thans for all your inputs. By far, only Saeed Amrollahi's solution
similar to what I want though a little complex (in the solution, a
user of the static vector has to go across a wrapper object before it
can access the member). Derive from std::vector should work, and can
keep the accessing code simple, but this still involes creating of
another class. Anyway, methods like
td::vector<int> NonPOD::foo(SIZE,4.4)
or

std::vector< int > const Class::staticVect(
begin( something), end( something) )

simply don't work since they both get too much limitation. What I
need to put into the vector in initial time is very specific data,
filling the vector with many default value or a regular serial is not
enought.

If all above is what C++ can do for the specific problem, it is a
shame of the language, but I don't believe it can be true. We must
did the following work in C for many many times:

// file: foo.c

static const int my_magic_code_table [] {
1,
9,
103,
2,
...
};

Now I sure you see what I was looking for is just a equivalent of
above in C++ as simple as we can approach. Anything else? Thanks.
 
L

Lionel B

We must did the
following work in C for many many times:

// file: foo.c

static const int my_magic_code_table [] {
1,
9,
103,
2,
...
};

Now I sure you see what I was looking for is just a equivalent of above
in C++ as simple as we can approach.

Doh! Why didn't you just say that in the first place?

// foo.hpp:

class Foo
{
private:
static const int my_magic_code_table[];
public:
static const std::vector<int> my_magic_code_vector;
};

// foo.cpp:

const int Foo::my_magic_code_table[] =
{
1,
9,
103,
2
};

const std::vector<int> Foo::my_magic_code_vector(
Foo::my_magic_code_table,
Foo::my_magic_code_table + sizeof(Foo::my_magic_code_table)/sizeof(int)
);

Although I'm not sure why you'd want a vector at all here
 
M

Michael DOUBEZ

Steven Woody a écrit :
If all above is what C++ can do for the specific problem, it is a
shame of the language, but I don't believe it can be true. We must
did the following work in C for many many times:

// file: foo.c

static const int my_magic_code_table [] {
1,
9,
103,
2,
...
};

Now I sure you see what I was looking for is just a equivalent of
above in C++ as simple as we can approach. Anything else? Thanks.

There is still boost.assign:
http://www.boost.org/doc/libs/1_35_0/libs/assign/doc/index.html

If I understand correctly (I have never used it), this will give
something like:

const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);
 
S

Steven Woody

We must did the
following work in C for many many times:
// file: foo.c
static const int my_magic_code_table [] {
1,
9,
103,
2,
...
};
Now I sure you see what I was looking for is just a equivalent of above
in C++ as simple as we can approach.

Doh! Why didn't you just say that in the first place?

// foo.hpp:

class Foo
{
private:
static const int my_magic_code_table[];
public:
static const std::vector<int> my_magic_code_vector;

};

// foo.cpp:

const int Foo::my_magic_code_table[] =
{
1,
9,
103,
2

};

const std::vector<int> Foo::my_magic_code_vector(
Foo::my_magic_code_table,
Foo::my_magic_code_table + sizeof(Foo::my_magic_code_table)/sizeof(int)
);

Although I'm not sure why you'd want a vector at all here

Because what I given is merely an example, I made it to make the
sample code simple so that suitable to post on usenet. In practice,
my table not only contains plain integers, I contains NON-POD objects,
that's one of the reason I choice std::vector. I am looking for a
general solution.
 
J

James Kanze

[...]
Anyway, methods like
simply don't work since they both get too much limitation. What I
need to put into the vector in initial time is very specific data,
filling the vector with many default value or a regular serial is not
enought.

But what is the specific data? If it's known at compile time
(or even if it's not---"something" can be an istream_iterator),
you can use the second. And if you don't know it until after
entering main, you can't make the vector const.
If all above is what C++ can do for the specific problem, it
is a shame of the language, but I don't believe it can be
true.

Well, I've yet to find a case where the template constructor
taking two iterators wouldn't work (and the data was known
before hand, of course). And you can always use something like:

std::vector< int > const Class::staticVector(
someFunctionReturningAVectorOfInt() ) ;

Which allows practically anything.

(Vector is, of course, an example; most of the time, for const
objects with static lifetime, I'll just use a C style array,
preferrably of POD type, to avoid any possible order of
initialization issues. But I regularly initialize static
std::map said:
We must did the following work in C for many many times:
// file: foo.c

static const int my_magic_code_table [] {
1,
9,
103,
2,
...
};

Well, that works in C++ as well, and I often use it.
Now I sure you see what I was looking for is just a equivalent
of above in C++ as simple as we can approach. Anything else?

At present, it's not possible to just list the entries directly
if the container type has a constructor. (Note that
boost::array doesn't have a constructor, explicitly to allow
this type of initialization. But it does require that you state
the size up front.) The next version of the standard should
support something similar, but in the meantime, you need the
extra object:

namespace {
int const initializers[] = {
// ...
} ;
}
std::vector< int > const Class::staticMember(
begin( initializers ), end( initializers ) ) ;

(With, of course, the usual definitions for begin and end:

template< typename T, size_t N >
T*
begin( T (&array)[ N ] )
{
return array ;
}

template< typename T, size_t N >
T*
end( T (&array)[ N ] )
{
return array + N ;
}

But you should already have those in your tool kit.)
 
J

James Kanze

On Jul 15, 10:47 pm, Lionel B <[email protected]> wrote:

[...]
const int Foo::my_magic_code_table[] =
{
1,
9,
103,
2
};
const std::vector<int> Foo::my_magic_code_vector(
Foo::my_magic_code_table,
Foo::my_magic_code_table + sizeof(Foo::my_magic_code_table)/sizeof(int)
);
Although I'm not sure why you'd want a vector at all here
Because what I given is merely an example, I made it to make
the sample code simple so that suitable to post on usenet. In
practice, my table not only contains plain integers, I
contains NON-POD objects, that's one of the reason I choice
std::vector.

I don't understand. You can create a C style array of non-POD
objects.
I am looking for a general solution.

Which is what he just showed. I do this all the time with
std::map. (Although recently, I've taken to using a C style array
and std::find_if. For anything small enough for all of its
members to be listed in a source file, linear search is fast
enough, and using a C style array of POD types means I can use
static initialization, and avoid order of initialization
problems.)
 
J

James Kanze

Steven Woody a écrit :

[...]
If I understand correctly (I have never used it), this will give
something like:
const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);

If vector<>::push_back supported chaining, you wouldn't even
need that:

std::vector< int > const magic
= std::vector< int >().push_back( 1 )
.push_back( 9 )... ;

(Of course, in this case, a somewhat shorter name would be
appreciated:).)
 
M

Michael DOUBEZ

James Kanze a écrit :
Steven Woody a écrit :
[...]
There is still boost.assign:http://www.boost.org/doc/libs/1_35_0/libs/assign/doc/index.html
If I understand correctly (I have never used it), this will give
something like:
const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);

If vector<>::push_back supported chaining, you wouldn't even
need that:


The strcpy(), strcat, str... were designed for chaining but AFAIK, it is
rarely used that way. I guess it would also be marginally useful for
std::vector said:
std::vector< int > const magic
= std::vector< int >().push_back( 1 )
.push_back( 9 )... ;

That's hideous. :)
 
X

xtrigger303

James Kanze a écrit :
    [...]
There is still boost.assign:http://www.boost.org/doc/libs/1_35_0/libs/assign/doc/index.html
If I understand correctly (I have never used it), this will give
something like:
const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);
If vector<>::push_back supported chaining, you wouldn't even
need that:

The strcpy(), strcat, str... were designed for chaining but AFAIK, it is
rarely used that way. I guess it would also be marginally useful for
std::vector<>.


    std::vector< int > const magic
        = std::vector< int >().push_back( 1 )
                              .push_back( 9 )... ;

That's hideous. :)

Hi to all,
I use the following template to trigger static member functions (that
can be used to do any type of initalization ).
It always seemed to work in the few cases I've used it. The only doubt
is the constructor of the template, that refers to the static member
object to enforce instantiation. My doubt is that some compiler
optimization might throw that away. With gcc it never seems to happen
with any optimization.
Any comment?
Regards to all,
Francesco

#include <iostream>
#include <vector>

template< typename T >
class CAutoInitializer
{
protected:
// enforce sInit instantiation
CAutoInitializer() { return; sInit; }
private:
struct CInit { CInit() { T::StaticInitializer(); } };
static CInit sInit;
};

template< typename T >
typename CAutoInitializer< T >::CInit CAutoInitializer< T >::sInit;

//

class CSomething : CAutoInitializer< CSomething >
{
public:
// avoid static init fiasco
static std::vector< int > & GetVec()
{ static std::vector< int > sVec; return sVec; }

static void StaticInitializer()
{
std::cout << "Do anything you want here\n";
GetVec().push_back( 10 );
}
};

//

class CSomethingElse : CAutoInitializer< CSomethingElse >
{
public:
static void StaticInitializer()
{ std::cout << "Do something else here\n"; }
};

int main()
{
std::cout << "main\n";
CSomething obj1;
CSomethingElse obj2;
std::cin.get();
}
 
X

xtrigger303

James Kanze a écrit :
Steven Woody a écrit :
    [...]
There is still boost.assign:http://www.boost.org/doc/libs/1_35_0/libs/assign/doc/index.html
If I understand correctly (I have never used it), this will give
something like:
const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);
If vector<>::push_back supported chaining, you wouldn't even
need that:
The strcpy(), strcat, str... were designed for chaining but AFAIK, it is
rarely used that way. I guess it would also be marginally useful for
std::vector<>.
That's hideous. :)

Hi to all,
I use the following template to trigger static member functions (that
can be used to do any type of initalization ).
It always seemed to work in the few cases I've used it. The only doubt
is the constructor of the template, that refers to the static member
object to enforce instantiation. My doubt is that some compiler
optimization might throw that away. With gcc it never seems to happen
with any optimization.
Any comment?
Regards to all,
Francesco

#include <iostream>
#include <vector>

template< typename T >
class CAutoInitializer
{
protected:
    // enforce sInit instantiation
    CAutoInitializer() { return; sInit; }
private:
    struct CInit { CInit() { T::StaticInitializer(); } };
    static CInit sInit;

};

template< typename T >
typename CAutoInitializer< T >::CInit CAutoInitializer< T >::sInit;

//

class CSomething : CAutoInitializer< CSomething >
{
public:
    // avoid static init fiasco
    static std::vector< int > & GetVec()
    { static std::vector< int > sVec; return sVec; }

    static void StaticInitializer()
    {
        std::cout << "Do anything you want here\n";
        GetVec().push_back( 10 );
    }

};

//

class CSomethingElse : CAutoInitializer< CSomethingElse >
{
public:
    static void StaticInitializer()
    {  std::cout << "Do something else here\n"; }

};

int main()
{
    std::cout << "main\n";
    CSomething      obj1;
    CSomethingElse  obj2;
    std::cin.get();



}- Nascondi testo citato

- Mostra testo citato- Nascondi testo citato

- Mostra testo citato


Sorry,
the code I posted is broken if any other statically initialized object
will call GetVec() before the template static object is instantiated.
Fiasco!
The below code is more like it I think, but it's getting
convoluted.. :-(
Moreover it does not address multithreading issues.
Sorry again,
bye,
Francesco


#include <iostream>
#include <vector>

template< typename TDerivingClass, typename TStaticObject >
class CStaticInstanceAutoInit
{
public:
static TStaticObject & GetInstance()
{
static bool sInit = TDerivingClass::StaticInitializer();
return GetUnsafe();
}
protected:
static TStaticObject & GetUnsafe()
{
static TStaticObject sObj;
return sObj;
}
CStaticInstanceAutoInit() { return; sInit; }
private:
struct CInit { CInit()
{ CStaticInstanceAutoInit::GetInstance(); } };
static CInit sInit;
};

//
template said:
CStaticInstanceAutoInit< TDerivingClass, TStaticObject

//

class CSomething : public CStaticInstanceAutoInit< CSomething,
std::vector< int > >
{
public:
static bool StaticInitializer( void )
{
std::cout << "init static instance something\n";
GetUnsafe().push_back( 13 );
return true;
}
};

//

int main()
{
std::cout << "main\n";
CSomething obj1;
obj1.GetInstance();
obj1.GetInstance();
std::cin.get();
}
 
J

James Kanze

James Kanze a écrit :
Steven Woody a écrit :
[...]
There is still
boost.assign:http://www.boost.org/doc/libs/1_35_0/libs/assign/doc/index.html
If I understand correctly (I have never used it), this will give
something like:
const std::vector<int> magic_code=list_of(1)(9)(103)(2)...(42);
If vector<>::push_back supported chaining, you wouldn't even
need that:
The strcpy(), strcat, str... were designed for chaining but
AFAIK, it is rarely used that way.

That's because the return value isn't the one you'd want to
chain.
I guess it would also be marginally useful for std::vector<>.
That's hideous. :)

It's a more or less standard idiom in some OO circles. With
such a long and awkward name, it isn't really very pretty. But
globally, the policy of having all mutators return *this as a
non-const reference can occasionally be useful.
 
S

Steven Woody

On Jul 15, 12:05 pm, Steven Woody <[email protected]> wrote:
[...]

Anyway, methods like
td::vector<int> NonPOD::foo(SIZE,4.4) or
std::vector< int > const Class::staticVect(
begin( something), end( something) )
simply don't work since they both get too much limitation. What I
need to put into the vector in initial time is very specific data,
filling the vector with many default value or a regular serial is not
enought.

But what is the specific data? If it's known at compile time
(or even if it's not---"something" can be an istream_iterator),
you can use the second. And if you don't know it until after
entering main, you can't make the vector const.
If all above is what C++ can do for the specific problem, it
is a shame of the language, but I don't believe it can be
true.

Well, I've yet to find a case where the template constructor
taking two iterators wouldn't work (and the data was known
before hand, of course). And you can always use something like:

std::vector< int > const Class::staticVector(
someFunctionReturningAVectorOfInt() ) ;

This seems interesting! I will try right now. And, in my real
program, the elements contained in the std::vector are actually
std::pair objects.
 
J

James Kanze

On Jul 16, 4:46 pm, James Kanze <[email protected]> wrote:

[...]
This seems interesting! I will try right now. And, in my real
program, the elements contained in the std::vector are actually
std::pair objects.

std::pair of what?

If possible, I would urge you to consider replacing std::pair
with a POD struct, and using either tr1::array or a C style
array with static initializers. That ensures that you will
never encounter an order of initialization problem, and will
work just as well as std::vector. (Most of the time I've used
the solution I just explained has been with std::map. And
looking something up in an std::map can be significantly faster
than using a linear search over an array. Although... unless
the number of elements is large, the difference often isn't
important.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top