Why can't a static data item be initialized?

I am trying to register a bunch of classes with factory at boot time. My strategy is to use static initialization to make sure that the main () factory is ready to go before starting. This strategy seems to work when I link my library dynamically, but not when I link statically; when I bind statically, only some of my static data members are initialized.

Say my factory builds cars. I have CarCreator classes that can create multiple machines, but not all. I want the factory to collect all these CarCreator classes so that the code looking for a new car can go to the factory without knowing who will make the actual construction.

So, I have a

CarTypes.hpp

enum CarTypes
{
   prius = 0,
   miata,
   hooptie,
   n_car_types
};

MyFactory.hpp

class CarCreator
{
public:
   virtual Car * create_a_car( CarType ) = 0;
   virtual std::list< CarTypes > list_cars_I_create() = 0;
};

class MyFactory // makes cars
{
public:
   Car * create_car( CarType type );
   void factory_register( CarCreator * )

   static MyFactory * get_instance(); // singleton
private:
   MyFactory();

   std::vector< CarCreator * > car_creator_map;
};

MyFactory.cpp

MyFactory:: MyFactory() : car_creator_map( n_car_types );

MyFactory * MyFactory::get_instance() {
   static MyFactory * instance( 0 ); /// Safe singleton
   if ( instance == 0 ) {
      instance = new MyFactory;
   }
   return instance;
}

void MyFactory::factory_register( CarCreator * creator )
{
   std::list< CarTypes > types = creator->list_cars_I_create();
   for ( std::list< CarTypes >::const_iteator iter = types.begin();
         iter != types.end(); ++iter ) {
      car_creator_map[ *iter ] = creator;
   }
}

Car * MyFactory::create_car( CarType type ) 
{
   if ( car_creator_map[ type ] == 0 ) { // SERIOUS ERROR!
      exit();
   }
   return car_creator_map[ type ]->create_a_car( type );
}

...

:

Miata.cpp

class Miata : public Car {...};

class MiataCreator : public CarCreator {
public:
   virtual Car * create_a_car( CarType );
   virtual std::list< CarTypes > list_cars_I_create();
private:
   static bool register_with_factory();
   static bool registered;
};

bool MiataCreator::register_with_factory()
{
   MyFactory::get_instance()->factory_register( new MiataCreator );
   return true;
}

bool MiataCreator::registered( MiataCreator::register_with_factory() );

...

: , MiataCreator:: registered , , .

, - factory Miata, miata car_creator_map NULL, .

- , - ? , ? CarCreator ; .cpp. , - MyFactory:: factory_register?

?

iall CarCreators , factory, , . , CarCreators , - factory .

...

, , :

1) singleton factory . a) , .

2) singleton factory , CarCreators (.. ) a) singleton, singleton . , , MiataCreator's::register_with_factory: .

+5
6

, , Factory.

, , .

, , :

  • , ( .cpp),
  • , , , .

, , , , - .

, MiataCreator:: ( Miata.cpp), , MyFactory:: create_car ( MyFactory.cpp) .

undefined, , , , , , (, ) , , .

, , Miata.cpp, MyFactory factory . , , . -.

+7

(.o) , , (.a), , , .

, , .

, - , , .

+3

, libaries, .o , . MiataCreator:: - Miata.cpp, , exe, -

nm objdump ( dumpbin, ), MiataCreator:: register exe .

, , ..

+1

, miata ? ?
, , - main() (, ), MiataCreator:: registered ( )

0

, .

'bool MiataCreator:: registered' os, lib (, /global, lib [ , undefined ])

"bool MiataCreator:: register_with_factory()", , - . , , .

, :

// Return the factory by reference rather than pointer.
// If you return by pointer the user has to assume it could be NULL
// Also the way you were creating the factory the destructor was never
// being called (though not probably a big deal here) so there was no
// cleanup, which may be usefull in the future. And its just neater.
MyFactory& MyFactory::get_instance()
{
    static MyFactory   instance; /// Safe singleton 
    return instance;
}

​​ . - , . factory .

bool MiataCreator::register_with_factory()
{
     MyFactory::get_instance()->factory_register( new MiataCreator );
     return true;
}
//
// I would hope that the linker does not optimize this out (but you should check).
// But the linker only pulls from (or searches in) static libraries 
// for references that are explicitly not defined.
bool MiataCreator::registered( MiataCreator::register_with_factory() );

:

MiataCreator::MiataCreator()
{
    // I would change factory_register to take a reference.
    // Though I would store it internall as a pointer in a vector.
    MyFactory::getInstance().factory_register(*this);
}

// In Cpp file.
static MiataCreator   factory;

​​ ++ , ( , bool , , ).

, 2c .

0

With gcc you can add -Wl,--whole-archive myLib.a --Wl,--no-whole-archive. This will force the linker to include objects, even if they are not mentioned. This, however, is not portable.

0
source

All Articles