Mimicking Javas static class initializer in C++

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Andreas Wollschlaeger

    #1

    Mimicking Javas static class initializer in C++

    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<Thingxx;
    static
    {
    xx = new Vector<Thing>(4 2);
    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_cha nnels_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_in itializer();
    }




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

    #include "VPNChannel .h"

    uint32_t VPNChannel::smA llocated_channe ls_map(static_c lass_initialize r());

    uint32_t VPNChannel::sta tic_class_initi alizer()
    {
    for (int i=0; i < MAX_CHANNELS; ++i)
    {
    VPNChannel::smI nstances[i] = (VPNChannel *)NULL;
    }
    return (uint32_t)0;
    }



    with this idea in mind:

    static_class_in itializer() 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_ch annels_map).
    To my surprise, this compiles fine, but gives a linker error:

    VPNChannel.o(.t ext+0x19):VPNCh annel.cpp: undefined reference to
    `VPNChannel::sm Instances'
    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

  • Victor Bazarov

    #2
    Re: Mimicking Javas static class initializer in C++

    Andreas Wollschlaeger wrote:
    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<Thingxx;
    static
    {
    xx = new Vector<Thing>(4 2);
    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_cha nnels_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_in itializer();
    }
    >
    >
    >
    >
    VPNChannel.cpp
    --------------
    >
    #include "VPNChannel .h"
    >
    uint32_t VPNChannel::smA llocated_channe ls_map(static_c lass_initialize r());
    >
    uint32_t VPNChannel::sta tic_class_initi alizer()
    {
    for (int i=0; i < MAX_CHANNELS; ++i)
    {
    VPNChannel::smI nstances[i] = (VPNChannel *)NULL;
    }
    return (uint32_t)0;
    }
    >
    >
    >
    with this idea in mind:
    >
    static_class_in itializer() 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_ch annels_map).
    To my surprise, this compiles fine, but gives a linker error:
    >
    VPNChannel.o(.t ext+0x19):VPNCh annel.cpp: undefined reference to
    `VPNChannel::sm Instances'
    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?
    ------------------------------- Header:
    class Foo
    {
    static vector<Thingxx;
    public:
    ...
    };

    ------------------------------- Implementation file:

    vector<Thingyou r_static_initia liser()
    {
    vector<Thingv(4 2);
    for (int i = 0; i < 42; ++i)
    v[i] = ...; // whatever specific you want to get

    return v;
    }

    vector<ThingFoo ::xx = your_static_ini tialiser();
    ....

    (presuming you include all the relevant headers for 'vector', etc.)

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask

    Comment

    • Lars Tetzlaff

      #3
      Re: Mimicking Javas static class initializer in C++

      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<Thingxx;
      static
      {
      xx = new Vector<Thing>(4 2);
      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_cha nnels_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_in itializer();
      }
      >
      >
      >
      >
      VPNChannel.cpp
      --------------
      >
      #include "VPNChannel .h"
      >
      uint32_t VPNChannel::smA llocated_channe ls_map(static_c lass_initialize r());
      >
      uint32_t VPNChannel::sta tic_class_initi alizer()
      {
      for (int i=0; i < MAX_CHANNELS; ++i)
      {
      VPNChannel::smI nstances[i] = (VPNChannel *)NULL;
      }
      return (uint32_t)0;
      }
      >
      >
      >
      with this idea in mind:
      >
      static_class_in itializer() 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_ch annels_map).
      To my surprise, this compiles fine, but gives a linker error:
      >
      VPNChannel.o(.t ext+0x19):VPNCh annel.cpp: undefined reference to
      `VPNChannel::sm Instances'
      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<Thi ngxx;
      static class MyVector : public std::vector<Thi ng*>{ public:
      MyVector(); } yy;
      };


      xx.cpp:

      #include <xx.h>

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

      Foo::MyVector Foo::yy;



      Lars

      Comment

      • Lars Tetzlaff

        #4
        Re: Mimicking Javas static class initializer in C++

        Lars Tetzlaff schrieb:
        xx.cpp:
        >
        #include <xx.h>
        >
        std::vector<Thi ngFoo::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

        Comment

        • Juha Nieminen

          #5
          Re: Mimicking Javas static class initializer in C++

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

          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.

          Comment

          • Andreas Wollschlaeger

            #6
            Re: Mimicking Javas static class initializer in C++

            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<Thi ngxx;
            static class MyVector : public std::vector<Thi ng*>{ public:
            MyVector(); } yy;
            };
            >
            >
            xx.cpp:
            >
            #include <xx.h>
            >
            std::vector<Thi ngFoo::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 "cplusplusi sh" than my previous
            attempt :-) Tx to you and the other folks, added me some more insight to
            C++ this evening!

            Cheers
            Andreas

            Comment

            • Jeff Schwab

              #7
              Re: Mimicking Javas static class initializer in C++

              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<Thi ngxx;
              > static class MyVector : public std::vector<Thi ng*>{ public:
              >MyVector(); } yy;
              >};
              >>
              >>
              >xx.cpp:
              >>
              >#include <xx.h>
              >>
              >std::vector<Th ingFoo::xx( 42 );
              >Foo::MyVector: :MyVector()
              >{
              > for( int i = 0; i<42; ++i ) {
              > yy.push_back( new Thing() );
              > }
              >}
              >>
              >Foo::MyVecto r 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 "cplusplusi sh" 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.

              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.

              Comment

              • Ian Collins

                #8
                Re: Mimicking Javas static class initializer in C++

                Jeff Schwab wrote:
                Andreas Wollschlaeger wrote:
                >Lars Tetzlaff schrieb:
                >>>
                >>xx.h:
                >>>
                >>#include <vector>
                >>>
                >>class Thing
                >>{
                >>};
                >>>
                >>class Foo
                >>{
                >>private:
                >> static std::vector<Thi ngxx;
                >> static class MyVector : public std::vector<Thi ng*>{ public:
                >>MyVector(); } yy;
                >>};
                >>>
                >>>
                >>xx.cpp:
                >>>
                >>#include <xx.h>
                >>>
                >>std::vector<T hingFoo::xx( 42 );
                >>Foo::MyVector ::MyVector()
                >>{
                >> for( int i = 0; i<42; ++i ) {
                >> yy.push_back( new Thing() );
                >> }
                >>}
                >>>
                >>Foo::MyVect or 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 "cplusplusi sh" 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<Thi ng*>
                {
                public:
                MyVector();
                } yy;

                --
                Ian Collins

                Comment

                • Jeff Schwab

                  #9
                  Re: Mimicking Javas static class initializer in C++

                  Ian Collins wrote:
                  Jeff Schwab wrote:
                  >Andreas Wollschlaeger wrote:
                  >>Lars Tetzlaff schrieb:
                  >>>xx.h:
                  >>>>
                  >>>#include <vector>
                  >>>>
                  >>>class Thing
                  >>>{
                  >>>};
                  >>>>
                  >>>class Foo
                  >>>{
                  >>>private:
                  >>> static std::vector<Thi ngxx;
                  >>> static class MyVector : public std::vector<Thi ng*>{ public:
                  >>>MyVector() ; } yy;
                  >>>};
                  >>>>
                  >>>>
                  >>>xx.cpp:
                  >>>>
                  >>>#include <xx.h>
                  >>>>
                  >>>std::vector< ThingFoo::xx( 42 );
                  >>>Foo::MyVecto r::MyVector()
                  >>>{
                  >>> for( int i = 0; i<42; ++i ) {
                  >>> yy.push_back( new Thing() );
                  >>> }
                  >>>}
                  >>>>
                  >>>Foo::MyVecto r 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 "cplusplusi sh" 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<Thi ng*>
                  {
                  public:
                  MyVector();
                  } yy;
                  >
                  True that. :)

                  Comment

                  • Lars Tetzlaff

                    #10
                    Re: Mimicking Javas static class initializer in C++

                    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<Thi ngxx;
                    >> static class MyVector : public std::vector<Thi ng*>{ public:
                    >>MyVector(); } yy;
                    >>};
                    >>>
                    >>>
                    >>xx.cpp:
                    >>>
                    >>#include <xx.h>
                    >>>
                    >>std::vector<T hingFoo::xx( 42 );
                    >>Foo::MyVector ::MyVector()
                    >>{
                    >> for( int i = 0; i<42; ++i ) {
                    >> yy.push_back( new Thing() );
                    >> }
                    >>}
                    >>>
                    >>Foo::MyVect or 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 "cplusplusi sh" 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

                    Comment

                    • blargg

                      #11
                      Re: Mimicking Javas static class initializer in C++

                      In article <49062fa0$0$326 68$9b4e6d93@new sspool2.arcor-online.net>,
                      Andreas Wollschlaeger <meister.possel @arcor.dewrote:
                      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<Thingxx;
                      static
                      {
                      xx = new Vector<Thing>(4 2);
                      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<Thingxx;
                      }

                      // Foo.cpp
                      vector<ThingFoo ::xx;

                      Foo::Foo()
                      {
                      if ( xx.empty() )
                      {
                      xx = new Vector<Thing>(4 2);
                      for (int i=0; i < xx.size(); ++i)
                      xx [o] = new Thing();
                      }
                      }

                      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.

                      Comment

                      • Richard Herring

                        #12
                        Re: Mimicking Javas static class initializer in C++

                        In message <blargg.h4g-291008041216000 1@192.168.1.4>, blargg
                        <blargg.h4g@gis hpuppy.comwrite s
                        >In article <49062fa0$0$326 68$9b4e6d93@new sspool2.arcor-online.net>,
                        >Andreas Wollschlaeger <meister.possel @arcor.dewrote:
                        >
                        >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<Thingxx;
                        > static
                        > {
                        > xx = new Vector<Thing>(4 2);
                        > 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
                        >initializati on will never run.
                        >
                        // Foo.hpp
                        class Foo {
                        public:
                        Foo();
                        >
                        private:
                        static vector<Thingxx;
                        }
                        >
                        // Foo.cpp
                        vector<ThingFoo ::xx;
                        >
                        Foo::Foo()
                        {
                        if ( xx.empty() )
                        {
                        xx = new Vector<Thing>(4 2);
                        ???
                        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

                        Comment

                        Working...