Mimicking Javas static class initializer in C++

  • Thread starter Andreas Wollschlaeger
  • Start date
A

Andreas Wollschlaeger

Hi folks,

as the subject says, i'm a poor Java programmer trying to transfer some
of his wisdom into C++ world... here is what im trying to do this evening:

Java has a nifty feature called a static class initializer - something
like this:

public class Foo
{
private static Vector<Thing> xx;
static
{
xx = new Vector<Thing>(42);
for (int i=0; i < xx.size(); ++i)
xx.set(i, new Thing());
}
}

where the static{} block is called once (when the class is first used),
thus suitable for complex initializations of static members.

Now i would like to have this in C++, can this be done?
Here is my current approach:

VPNChannel.h
------------

class VPNChannel
{
static const int MAX_CHANNELS = 4;

// Bitmask of allocated channels
static uint32_t smAllocated_channels_map;

//
// Vector holding all possible instances of VPNChannel
//
static VPNChannel *smInstances[MAX_CHANNELS];

//
// Static initializer
// This is kinda kludge to mimic Javas static {} class initializer
//
static uint32_t static_class_initializer();
}




VPNChannel.cpp
--------------

#include "VPNChannel.h"

uint32_t VPNChannel::smAllocated_channels_map(static_class_initializer());

uint32_t VPNChannel::static_class_initializer()
{
for (int i=0; i < MAX_CHANNELS; ++i)
{
VPNChannel::smInstances = (VPNChannel *)NULL;
}
return (uint32_t)0;
}



with this idea in mind:

static_class_initializer() is used to do complex initialization of an
static array, it returns a dummy zero value, so it can be used to
initialze another static variable (smAllocated_channels_map).
To my surprise, this compiles fine, but gives a linker error:

VPNChannel.o(.text+0x19):VPNChannel.cpp: undefined reference to
`VPNChannel::smInstances'
collect2: ld returned 1 exit status
(I'm using MinGW 3.4.2)

Any hint, what goes wrong here? Or maybe a better, more c++ish approach
to static initialization?

Cheers and Greetings
Andreas
 
L

Lars Tetzlaff

Andreas said:
Hi folks,

as the subject says, i'm a poor Java programmer trying to transfer some
of his wisdom into C++ world... here is what im trying to do this evening:

Java has a nifty feature called a static class initializer - something
like this:

public class Foo
{
private static Vector<Thing> xx;
static
{
xx = new Vector<Thing>(42);
for (int i=0; i < xx.size(); ++i)
xx.set(i, new Thing());
}
}

where the static{} block is called once (when the class is first used),
thus suitable for complex initializations of static members.

Now i would like to have this in C++, can this be done?
Here is my current approach:

VPNChannel.h
------------

class VPNChannel
{
static const int MAX_CHANNELS = 4;

// Bitmask of allocated channels
static uint32_t smAllocated_channels_map;

//
// Vector holding all possible instances of VPNChannel
//
static VPNChannel *smInstances[MAX_CHANNELS];

//
// Static initializer
// This is kinda kludge to mimic Javas static {} class initializer
//
static uint32_t static_class_initializer();
}




VPNChannel.cpp
--------------

#include "VPNChannel.h"

uint32_t VPNChannel::smAllocated_channels_map(static_class_initializer());

uint32_t VPNChannel::static_class_initializer()
{
for (int i=0; i < MAX_CHANNELS; ++i)
{
VPNChannel::smInstances = (VPNChannel *)NULL;
}
return (uint32_t)0;
}



with this idea in mind:

static_class_initializer() is used to do complex initialization of an
static array, it returns a dummy zero value, so it can be used to
initialze another static variable (smAllocated_channels_map).
To my surprise, this compiles fine, but gives a linker error:

VPNChannel.o(.text+0x19):VPNChannel.cpp: undefined reference to
`VPNChannel::smInstances'
collect2: ld returned 1 exit status
(I'm using MinGW 3.4.2)

Any hint, what goes wrong here? Or maybe a better, more c++ish approach
to static initialization?

Cheers and Greetings
Andreas


You do not need to allocate every object with new in C++, so if you only
need a vector of Thing, use xx. If you need to allocate Thing on the
heap, use yy;


xx.h:

#include <vector>

class Thing
{
};

class Foo
{
private:
static std::vector<Thing> xx;
static class MyVector : public std::vector<Thing*>{ public:
MyVector(); } yy;
};


xx.cpp:

#include <xx.h>

std::vector<Thing> Foo::xx( 42 );
Foo::MyVector::MyVector()
{
for( int i = 0; i<42; ++i ) {
yy.push_back( new Thing() );
}
}

Foo::MyVector Foo::yy;



Lars
 
L

Lars Tetzlaff

Lars said:
xx.cpp:

#include <xx.h>

std::vector<Thing> Foo::xx( 42 );
Foo::MyVector::MyVector()
{
for( int i = 0; i<42; ++i ) {
yy.push_back( new Thing() );
}
}

Foo::MyVector Foo::yy;



Lars

Should be

push_back( new Thing() );

instead of

yy.push_back( new Thing() );


Lars
 
J

Juha Nieminen

Andreas said:
Now i would like to have this in C++, can this be done?

One possible approach is to wrap the static data, which must be
initialized with code, inside a class/struct:

class Foo
{
struct XX
{
std::vector<Thing> xx;

XX()
{
// Initialize 'xx' here.
// (You could also implement this in the compilation unit
// to reduce clutter in the header file.)
}
};

static XX xx;
};


Then in the compilation unit you define the XX instance:

Foo::XX Foo::xx; // Will be initialized with the XX constructor

Of course you'll have to access the vector with "xx.xx" from now on.
With a logical and modular naming scheme you can make it less ugly.
 
A

Andreas Wollschlaeger

Lars said:
You do not need to allocate every object with new in C++, so if you only
need a vector of Thing, use xx. If you need to allocate Thing on the
heap, use yy;


xx.h:

#include <vector>

class Thing
{
};

class Foo
{
private:
static std::vector<Thing> xx;
static class MyVector : public std::vector<Thing*>{ public:
MyVector(); } yy;
};


xx.cpp:

#include <xx.h>

std::vector<Thing> Foo::xx( 42 );
Foo::MyVector::MyVector()
{
for( int i = 0; i<42; ++i ) {
yy.push_back( new Thing() );
}
}

Foo::MyVector Foo::yy;

Well, great, this was just what i have been looking for: encapsulating
the statics initialization in some inner class and its default
constructor - much more elegant and "cplusplusish" than my previous
attempt :) Tx to you and the other folks, added me some more insight to
C++ this evening!

Cheers
Andreas
 
I

Ian Collins

Jeff said:
I can see why that solution would look nice to a Java developer, but in
general, it's a bad idea to derive your own classes from the standard
ones; it is especially non-c++ish.
Unless you make the inheritance private, which would work equally well here:

static class MyVector : std::vector<Thing*>
{
public:
MyVector();
} yy;
 
L

Lars Tetzlaff

Jeff said:
I can see why that solution would look nice to a Java developer, but in
general, it's a bad idea to derive your own classes from the standard
ones; it is especially non-c++ish.

C++ methods aren't virtual by default; they're more like final methods
in Java. In particular, their destructors aren't virtual, so if ever an
instance of a derived type is deleted through a pointer to a base with a
non-virtual destructor, nasty things will happen. You're much better
off in this case with Victor or Juha's solutions, both of which are fine.

Since the destruction of yy happens in the implementation file the type
is known to the compiler and the right destructor is called. The class
was ment *only* to initialize the static member. Generally I would agree
to your comment but not in the situation of initializing a static member
or a local variable.
FWIW, most should-be-simple things aren't as complicated as this; there
are just a few "don't do thats" that you have to pick up when you get
started, and you happen to have gotten some mediocre advice (no offense,
Lars) right off the bat.

Lars
 
J

James Kanze

[...]
Well, great, this was just what i have been looking for:
encapsulating the statics initialization in some inner class
and its default constructor - much more elegant and
"cplusplusish" than my previous attempt :) Tx to you and the
other folks, added me some more insight to C++ this evening!

Just a bit of additional information. This isn't quite like
Java. C++ is statically linked, and the initialization code will
be executed before entering main (with all existing compilers,
anyway), where as Java uses lazy dynamic loading, and the
initialization code won't be executed until you load the class,
which won't happen until you use something in it. The C++ model
has one definite advantage: the initialization code will be
executed even if you never directly reference the class (e.g.
because it is a derived class, which registers its factory in
the static initializer---a frequent C++ idiom). It also has a
downside: the order of initialization isn't defined, so if one
static initializer depends on another, you may have problems.
(The usual work-around for this is to use the singleton idiom.)
 
R

Richard Herring

blargg said:
Trying to make as literal a translation here. This will initialize things
the first time a Foo object is created; if no Foo is ever created, this
initialization will never run.

// Foo.hpp
class Foo {
public:
Foo();

private:
static vector<Thing> xx;
}

// Foo.cpp
vector<Thing> Foo::xx;

Foo::Foo()
{
if ( xx.empty() )
{
xx = new Vector<Thing>(42);

???
xx is a vector, not a pointer.
for (int i=0; i < xx.size(); ++i)
xx [o] = new Thing();

.... and it contains Things, not pointers. You appear to be writing Java
here.
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top