Error when initializing static variables

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

    #1

    Error when initializing static variables

    Hi,

    I have some problems using static variables which results in a core
    dump. I have attached code and coredump to the end of my message.

    I am trying to implement a kind of factory design. I have a base class
    with several sub classes. In runtime I want to create a instance of a
    sub class and assign it to a base class pointer. Nothing fancy about
    that. I also want to be able in runtime to decide witch type of sub
    class that is to be instantiated. Another requirement is that I want to
    be able to add new sub classes without changing the existing code base.
    To accomplish this I have made two classes that make up the
    factory-part of the design, Maker and SpecializedMake r. Maker contains
    a std::map with a key and a pointer to Maker. Then specializedMake r
    contains a static variable. All this is made with templates.

    The makerMap is defined first and then every sub class is able to
    define the static variable registerThis and by doing so adding a key
    and a factory method in makerMap. It may sound complicated, but is
    quite straight forward when looking at the code.

    I have tried to shorten the attached example, but it is still quite
    big. Sorry for the quite long post.

    I know that instantiation of static variables can be a source of
    trouble, but I could not find any other good way to do this.

    Using CC 5.3 on Solaris gives me a working application, but when
    upgrading to CC 5.7 my applications leaves a core dump instead.

    My questions are:
    1) Is there a better way to do this?
    2) Ip my code meet the standard (and should work)? Or was I lucky when
    it ran compiled with CC 5.3?
    3) I the order of initialisations of static members standardized (i.e.
    is the order fixed in one translation unit)?


    program terminated by signal SEGV (no mapping at the fault address)
    0x00013d2c: insert+0x002c: ld [%l0 + 4], %l0
    (dbx) where

    =>[1]
    __rwstd::__rb_t ree<std::basic_ string<char,std ::char_traits<c har>,std::alloc ator<char>[color=blue]
    >,std::pair<con st std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* >,__rwstd::__se lect1st<std::pa ir<const std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* >,std::basic_st ring<char,std:: char_traits<cha r>,std::allocat or<char> > >,std::less<std ::basic_string< char,std::char_ traits<char>,st d::allocator<ch ar> > >,std::allocato r<std::pair<con st std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* > > >::insert(0xffb ef6f8, 0x27188, 0xffbef690, 0x1, 0xff06b8c8, 0x46ad0), at 0x13d2c[/color]
    [2] SpecializedMake r<A,B,int>::Spe cializedMaker(0 x2716c, 0xffbef7e8,
    0xffbef7e7, 0xff3de79c, 0x222b0, 0x1), at 0x13350
    [3] __SLIP.INIT_A(0 x0, 0xff1421a0, 0xff13e5d8, 0xff1ea8d4, 0x222b0,
    0xff09bc20), at 0x1310c
    [4] __STATIC_CONSTR UCTOR(0x0, 0xff13c008, 0x16b48, 0xffffffff,
    0x222b0, 0x16ba4), at 0x1329c
    [5] 0x16c04(0x26fac , 0xff13c008, 0x16c18, 0x0, 0x0, 0x0), at 0x16c03

    ------------------------------------------------------------------------------

    The code looks like this:

    #include <iostream>
    #include <string>
    #include <map>

    //
    // Test classes
    //

    class A {

    public:
    A() : m_val(4711) {}
    int getVal() {return m_val;}
    private:
    int m_val;
    };

    class B : public A {
    public:
    B(int i) : m_val2(i) {}
    int getVal2() { return m_val2;}
    private:
    int m_val2;
    };


    //
    // Maker
    //
    template<class T, class U = int> class Maker
    {
    public:

    static T* newObject(const std::string& key, U arg)
    {
    Maker<T, U> * factory = 0;
    factory = (*m_makerMap.fi nd(key)).second ;
    if (factory != 0) {
    return factory->createObject(a rg);
    }
    else {
    return 0;
    }
    }

    protected:

    Maker (const std::string& key)
    {
    m_makerMap[const_cast<std: :string&>(key)] = this;
    }

    virtual T* createObject(U arg) const = 0;

    private:

    Maker() {}
    Maker(const Maker& right) {}
    Maker& operator= (const Maker& right) {}

    static std::map<std::s tring, Maker<T,U>* > m_makerMap;

    };


    //
    // SpecializedMake r
    //
    template<class T, class P, class U = int> class SpecializedMake r :
    public Maker <T, U>
    {

    public:

    T* createObject (U arg) const
    {
    return new P(arg);
    }

    private:

    SpecializedMake r(const std::string& key)
    : Maker <T, U>(key) {}

    static const SpecializedMake r<T, P, U> m_registerThis;

    };

    template <class T, class U>
    std::map<std::s tring, Maker<T, U>*> Maker<T, U>::m_makerMap ;

    const SpecializedMake r<A, B>
    SpecializedMake r<A, B>::m_registerT his("B");


    //
    // Main
    //
    int main(int argc, char** argv)
    {


    return 0;
    }

  • mlimber

    #2
    Re: Error when initializing static variables

    Diebels wrote:[color=blue]
    > Hi,
    >
    > I have some problems using static variables which results in a core
    > dump. I have attached code and coredump to the end of my message.
    >
    > I am trying to implement a kind of factory design. I have a base class
    > with several sub classes. In runtime I want to create a instance of a
    > sub class and assign it to a base class pointer. Nothing fancy about
    > that. I also want to be able in runtime to decide witch type of sub
    > class that is to be instantiated. Another requirement is that I want to
    > be able to add new sub classes without changing the existing code base.
    > To accomplish this I have made two classes that make up the
    > factory-part of the design, Maker and SpecializedMake r. Maker contains
    > a std::map with a key and a pointer to Maker. Then specializedMake r
    > contains a static variable. All this is made with templates.
    >
    > The makerMap is defined first and then every sub class is able to
    > define the static variable registerThis and by doing so adding a key
    > and a factory method in makerMap. It may sound complicated, but is
    > quite straight forward when looking at the code.
    >
    > I have tried to shorten the attached example, but it is still quite
    > big. Sorry for the quite long post.
    >
    > I know that instantiation of static variables can be a source of
    > trouble, but I could not find any other good way to do this.
    >
    > Using CC 5.3 on Solaris gives me a working application, but when
    > upgrading to CC 5.7 my applications leaves a core dump instead.
    >
    > My questions are:
    > 1) Is there a better way to do this?
    > 2) Ip my code meet the standard (and should work)? Or was I lucky when
    > it ran compiled with CC 5.3?
    > 3) I the order of initialisations of static members standardized (i.e.
    > is the order fixed in one translation unit)?
    >
    >
    > program terminated by signal SEGV (no mapping at the fault address)
    > 0x00013d2c: insert+0x002c: ld [%l0 + 4], %l0
    > (dbx) where
    >
    > =>[1]
    > __rwstd::__rb_t ree<std::basic_ string<char,std ::char_traits<c har>,std::alloc ator<char>[color=green]
    > >,std::pair<con st std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* >,__rwstd::__se lect1st<std::pa ir<const std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* >,std::basic_st ring<char,std:: char_traits<cha r>,std::allocat or<char> > >,std::less<std ::basic_string< char,std::char_ traits<char>,st d::allocator<ch ar> > >,std::allocato r<std::pair<con st std::basic_stri ng<char,std::ch ar_traits<char> ,std::allocator <char> >,Maker<A,int>* > > >::insert(0xffb ef6f8, 0x27188, 0xffbef690, 0x1, 0xff06b8c8, 0x46ad0), at 0x13d2c[/color]
    > [2] SpecializedMake r<A,B,int>::Spe cializedMaker(0 x2716c, 0xffbef7e8,
    > 0xffbef7e7, 0xff3de79c, 0x222b0, 0x1), at 0x13350
    > [3] __SLIP.INIT_A(0 x0, 0xff1421a0, 0xff13e5d8, 0xff1ea8d4, 0x222b0,
    > 0xff09bc20), at 0x1310c
    > [4] __STATIC_CONSTR UCTOR(0x0, 0xff13c008, 0x16b48, 0xffffffff,
    > 0x222b0, 0x16ba4), at 0x1329c
    > [5] 0x16c04(0x26fac , 0xff13c008, 0x16c18, 0x0, 0x0, 0x0), at 0x16c03
    >
    > ------------------------------------------------------------------------------
    >
    > The code looks like this:
    >
    > #include <iostream>
    > #include <string>
    > #include <map>
    >
    > //
    > // Test classes
    > //
    >
    > class A {
    >
    > public:
    > A() : m_val(4711) {}
    > int getVal() {return m_val;}
    > private:
    > int m_val;
    > };
    >
    > class B : public A {
    > public:
    > B(int i) : m_val2(i) {}
    > int getVal2() { return m_val2;}
    > private:
    > int m_val2;
    > };
    >
    >
    > //
    > // Maker
    > //
    > template<class T, class U = int> class Maker
    > {
    > public:
    >
    > static T* newObject(const std::string& key, U arg)
    > {
    > Maker<T, U> * factory = 0;
    > factory = (*m_makerMap.fi nd(key)).second ;
    > if (factory != 0) {
    > return factory->createObject(a rg);
    > }
    > else {
    > return 0;
    > }
    > }
    >
    > protected:
    >
    > Maker (const std::string& key)
    > {
    > m_makerMap[const_cast<std: :string&>(key)] = this;
    > }
    >
    > virtual T* createObject(U arg) const = 0;
    >
    > private:
    >
    > Maker() {}
    > Maker(const Maker& right) {}
    > Maker& operator= (const Maker& right) {}
    >
    > static std::map<std::s tring, Maker<T,U>* > m_makerMap;
    >
    > };
    >
    >
    > //
    > // SpecializedMake r
    > //
    > template<class T, class P, class U = int> class SpecializedMake r :
    > public Maker <T, U>
    > {
    >
    > public:
    >
    > T* createObject (U arg) const
    > {
    > return new P(arg);
    > }
    >
    > private:
    >
    > SpecializedMake r(const std::string& key)
    > : Maker <T, U>(key) {}
    >
    > static const SpecializedMake r<T, P, U> m_registerThis;
    >
    > };
    >
    > template <class T, class U>
    > std::map<std::s tring, Maker<T, U>*> Maker<T, U>::m_makerMap ;
    >
    > const SpecializedMake r<A, B>
    > SpecializedMake r<A, B>::m_registerT his("B");
    >
    >
    > //
    > // Main
    > //
    > int main(int argc, char** argv)
    > {
    >
    >
    > return 0;
    > }[/color]

    Interestingly, I had a very similar issue recently. See this thread,
    and particularly the posts from Nov 21 and after:



    The similarity is especially acute since you are using a static
    variable to register with the factory. See the cited thread for a
    standard conformant solution to that problem.

    One other thing I would suggest is getting rid of the static map in
    Maker<> and making the class a singleton instead. This would ensure
    that no "static initialization order fiasco" is in play. See this FAQ
    and following:



    Something like the "Meyers singleton" might be good enough (if not see
    _Modern C++ Design_, ch. 6 for other options):

    template<class T>
    class Singleton
    {
    public:
    static T& Instance();
    private:
    // Disabled functions
    Singleton();
    Singleton( const Singleton& );
    Singleton& operator=( const Singleton& );
    Singleton* operator&();
    ~Singleton();
    };

    template<class T>
    T& Singleton<T>::I nstance()
    {
    static T myObject;
    return myObject;
    }

    typedef Singleton< SpecializedMake r<A,B> > theMaker;

    void Foo()
    {
    std::auto_ptr<A > a( theMaker::Insta nce().createObj ect( 42 ) );
    // ...
    }

    Cheers! --M

    Comment

    • Diebels

      #3
      Re: Error when initializing static variables


      mlimber skrev:
      [color=blue]
      > One other thing I would suggest is getting rid of the static map in
      > Maker<> and making the class a singleton instead. This would ensure
      > that no "static initialization order fiasco" is in play. See this FAQ
      > and following:[/color]

      This is exactly what I am doing right now. It seems to work, but I have
      to convert some of the new code to templates and do some more testing
      before I am sure this is the way to go.

      Thanks!

      //daniel

      Comment

      • John Carson

        #4
        Re: Error when initializing static variables

        "Diebels" <daniel.grondal @gmail.com> wrote in message
        news:1134638296 .196863.85490@g 47g2000cwa.goog legroups.com[color=blue]
        > Hi,
        >
        > I have some problems using static variables which results in a core
        > dump. I have attached code and coredump to the end of my message.
        >[/color]
        [snip][color=blue]
        > The code looks like this:
        >
        > #include <iostream>
        > #include <string>
        > #include <map>
        >
        > //
        > // Test classes
        > //
        >
        > class A {
        >
        > public:
        > A() : m_val(4711) {}
        > int getVal() {return m_val;}
        > private:
        > int m_val;
        > };
        >
        > class B : public A {
        > public:
        > B(int i) : m_val2(i) {}
        > int getVal2() { return m_val2;}
        > private:
        > int m_val2;
        > };
        >
        >
        > //
        > // Maker
        > //
        > template<class T, class U = int> class Maker
        > {
        > public:
        >
        > static T* newObject(const std::string& key, U arg)
        > {
        > Maker<T, U> * factory = 0;
        > factory = (*m_makerMap.fi nd(key)).second ;
        > if (factory != 0) {
        > return factory->createObject(a rg);
        > }
        > else {
        > return 0;
        > }
        > }
        >
        > protected:
        >
        > Maker (const std::string& key)
        > {
        > m_makerMap[const_cast<std: :string&>(key)] = this;
        > }
        >
        > virtual T* createObject(U arg) const = 0;
        >
        > private:
        >
        > Maker() {}
        > Maker(const Maker& right) {}
        > Maker& operator= (const Maker& right) {}
        >
        > static std::map<std::s tring, Maker<T,U>* > m_makerMap;
        >
        > };
        >
        >
        > //
        > // SpecializedMake r
        > //
        > template<class T, class P, class U = int> class SpecializedMake r :
        > public Maker <T, U>
        > {
        >
        > public:
        >
        > T* createObject (U arg) const
        > {
        > return new P(arg);
        > }
        >
        > private:
        >
        > SpecializedMake r(const std::string& key)
        > : Maker <T, U>(key) {}
        >
        > static const SpecializedMake r<T, P, U> m_registerThis;
        >
        > };
        >
        > template <class T, class U>
        > std::map<std::s tring, Maker<T, U>*> Maker<T, U>::m_makerMap ;[/color]

        Adding

        template <>
        std::map<std::s tring, Maker<A>*> Maker<A>::m_mak erMap;

        here seems to solve the problem (though I don't fully understand what is
        going on).

        The omission of template<> from the next line is non-standard
        [color=blue]
        > const SpecializedMake r<A, B>
        > SpecializedMake r<A, B>::m_registerT his("B");
        >
        >
        > //
        > // Main
        > //
        > int main(int argc, char** argv)
        > {
        >
        >
        > return 0;
        > }[/color]


        --
        John Carson


        Comment

        Working...