Mimicking Javas static class initializer in C++

Discussion in 'C++' started by Andreas Wollschlaeger, Oct 27, 2008.

  1. 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
    Andreas Wollschlaeger, Oct 27, 2008
    #1
    1. Advertising

  2. Andreas Wollschlaeger schrieb:
    > 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
    Lars Tetzlaff, Oct 27, 2008
    #2
    1. Advertising

  3. Lars Tetzlaff schrieb:

    > 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
    Lars Tetzlaff, Oct 27, 2008
    #3
  4. Andreas Wollschlaeger wrote:
    > 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.
    Juha Nieminen, Oct 27, 2008
    #4
  5. Lars Tetzlaff schrieb:
    > Andreas Wollschlaeger schrieb:
    >> 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:

    > 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
    Andreas Wollschlaeger, Oct 27, 2008
    #5
  6. Andreas Wollschlaeger

    Ian Collins Guest

    Jeff Schwab wrote:
    > Andreas Wollschlaeger wrote:
    >> Lars Tetzlaff schrieb:
    >>>
    >>> 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!

    >
    > 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;

    --
    Ian Collins
    Ian Collins, Oct 27, 2008
    #6
  7. Jeff Schwab schrieb:
    > Andreas Wollschlaeger wrote:
    >> Lars Tetzlaff schrieb:
    >>> Andreas Wollschlaeger schrieb:
    >>>> 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:
    >>> 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!

    >
    > 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
    Lars Tetzlaff, Oct 28, 2008
    #7
  8. Andreas Wollschlaeger

    James Kanze Guest

    On Oct 27, 11:37 pm, Andreas Wollschlaeger <>
    wrote:
    > Lars Tetzlaff schrieb:
    > > Andreas Wollschlaeger schrieb:
    > >> 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:


    [...]
    > 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.)

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, Oct 29, 2008
    #8
  9. In message <blargg.h4g-2910080412160001@192.168.1.4>, blargg
    <> writes
    >In article <49062fa0$0$32668$-online.net>,
    >Andreas Wollschlaeger <> wrote:
    >
    >> 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?

    >
    >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.

    > }
    > }
    >
    >Here is a more general approach that separates the init code into its own
    >function:
    >
    > // Foo.hpp
    > class Foo {
    > public:
    > Foo();
    >
    > private:
    > static void first_use();
    > }
    >
    > // Foo.cpp
    > void Foo::first_use()
    > {
    > // initialize statics
    > }
    >
    > Foo::Foo()
    > {
    > static int call_once = (first_use(),0);
    > }
    >
    >You could use a less-hacky approach to having first_use() called only
    >once, like a helper class, but this is a more concise approach.


    --
    Richard Herring
    Richard Herring, Oct 29, 2008
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,830
    Thomas Hawtin
    Jun 9, 2006
  2. Samir Patel
    Replies:
    0
    Views:
    296
    Samir Patel
    Feb 6, 2004
  3. Frank Milverckowitz
    Replies:
    3
    Views:
    384
    sloan
    Jan 19, 2007
  4. chucky
    Replies:
    14
    Views:
    1,273
    Twisted
    Aug 2, 2007
  5. joes
    Replies:
    3
    Views:
    297
Loading...

Share This Page