На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: JoeUser, Qraizer, Hsilgos
  
> Нелокальные статические объекты и статические библиотеки, объекты могут и совсем не инициализироваться?
    Компилятор: идущий по стандарту с VS2012
    ОС: Windows


    Нашёл для себя интересную особенность, связанную с компоновщиком.
    Если в статической библиотеке есть объектные файлы на которые нет ссылок, то эти объектные файлы не компонуются с программой.
    Соответственно, не инициализируются любые статические объекты в этом файле.

    С одной стороны, всё логично.

    Но вот например, у меня есть код регистрирующий конструкторы классов в фабрике:
    ExpandedWrap disabled
      #include <Engine/Modules/ActorFactory.h>
      // unnamed namespase to hide from another places
      namespace
      {
          // specific factory
          IActor* CreateWall(World *world, const Vector2D location, const Vector2D scale, const Rotator rotation)
          {
              return new Wall(world, location, scale, rotation);
          }
       
          const std::string CLASS_ID = "Wall";
       
          // register specific factory in actor factory
          const bool registered = ActorFactory::Factory().registerActor(CLASS_ID, CreateWall);
      }


    Такой вот код включён в исходные коды разных объектов, дабы можно было изменять/удалять регистрации классов вместе с самими объектами.

    И всё было хорошо, но после вынесения всех таких классов в статическую библиотеку, часть из них перестала регистрироваться в фабрике.

    Однако, если, например, создавать хотя бы один объект класса Wall вручную, то объектный файл подключается, происходит регистрация, и остальные объекты этого класса нормально создаются.

    Пока не вижу хорошего решения этой проблемы:
    • Если вынести регистрации классов в основную программу, то это внесёт сложности при добавлении/удалении/модификации этих классов
    • Если вручную ссылаться на что-нибудь в этих единицах трансляции, то это будет очень неявно и когда-нибудь всё опять сломается


    Что можете посоветовать в данной ситуации?
      WhyNot
      Код фабрики покажи. А вообще такая регистрация плохая идея. Также как и статические переменные в либах.
      Если умеешь защищать программы, то умеешь их и ломать, но не наоборот.
      Документация как секс - лучше любая, чем никакой.
        Цитата Urich @
        Код фабрики покажи

        Код фабрики здесь не при чём. Компоновщик выбрасывает "неиспользуемый" код, вот и всё - проблема известная.
        Цитата Urich @
        А вообще такая регистрация плохая идея.

        Идея хорошая, способствующая слабой связности. Но компоновщик её вечно портит. Меня тоже волнует вопрос топикстартера.
        Цитата Urich @
        Также как и статические переменные в либах.

        :blink: С чего бы?
          Цитата MyNameIsIgor @
          Идея хорошая, способствующая слабой связности. Но компоновщик её вечно портит.

          Я с этой хорошей идей намучился. Пока у тебя в проекте одно место линковки, пока не используешь менеджеры памяти отличные от рантаймоских. Пока это только твой проект, у тебя все хорошо.
          Если умеешь защищать программы, то умеешь их и ломать, но не наоборот.
          Документация как секс - лучше любая, чем никакой.
            Цитата Urich @
            Пока у тебя в проекте одно место линковки

            Что такое "одно место линковки"?
            Цитата Urich @
            пока не используешь менеджеры памяти отличные от рантаймоских

            Не вижу проблем.
            Цитата Urich @
            Пока это только твой проект, у тебя все хорошо.

            Как раз IoC всегда помогало делать проект "не только моим".
              Цитата Urich @
              Код фабрики покажи.


              ActorFactory.h
              ExpandedWrap disabled
                #ifndef ACTOR_FACTORY
                #define ACTOR_FACTORY
                 
                #include <map>
                #include "../Core/World.h"
                 
                /**
                 * Factory that allows to create any type of registered actor by their name identifier.
                 *
                 * Based on pattern Factory in book Andrei Alexandrescu "Modern C++ Design: Generic Programming and Design Patterns Applied"
                 *
                 * ActorFactory is a singleton.
                 */
                class ActorFactory
                {
                public:
                    typedef IActor* (*CreateActorCallback)(World *world, const Vector2D location, const Vector2D scale, const Rotator rotation);
                private:
                    typedef std::map<std::string, CreateActorCallback> CallbackMap;
                public:
                    /**
                     * @return the single instance of the ActorFactory
                     */
                    static ActorFactory& Factory();
                 
                    /**
                     * Register new actor class by an identifier and a "create" function.
                     * If identifier already exists, factory will not be registered.
                     *
                     * @return true if class wasn't registered earlier
                     */
                    bool registerActor(std::string actorId, CreateActorCallback createFn);
                 
                    /**
                     * Unregister already registred class.
                     *
                     * @return true if class was unregistered
                     */
                    bool unregisterActor(std::string actorId);
                 
                    /**
                     * Create actor by identifier.
                     *
                     * @throws runtime_error when actorId is unknown
                     */
                    IActor* placeActor(std::string actorId, World *world, const Vector2D location, const Vector2D size, const Rotator rotation);
                private:
                    CallbackMap callbacks;
                 
                    static ActorFactory* singleInstance;
                 
                    /*
                     * Turn off unusable operations
                     */
                    ActorFactory();
                    ~ActorFactory();
                    ActorFactory(const ActorFactory&);
                    void operator=(const ActorFactory&);
                };
                 
                #endif


              ActorFactory.cpp
              ExpandedWrap disabled
                #include "ActorFactory.h"
                 
                ActorFactory* ActorFactory::singleInstance = nullptr;
                 
                ActorFactory::ActorFactory() {}
                ActorFactory::~ActorFactory() {}
                 
                ActorFactory& ActorFactory::Factory()
                {
                    if (ActorFactory::singleInstance == nullptr)
                    {
                        ActorFactory::singleInstance = new ActorFactory();
                    }
                 
                    return *ActorFactory::singleInstance;
                }
                 
                bool ActorFactory::registerActor(std::string actorId, CreateActorCallback createFn)
                {
                    return this->callbacks.insert(CallbackMap::value_type(actorId, createFn)).second;
                }
                 
                bool ActorFactory::unregisterActor(std::string actorId)
                {
                    return this->callbacks.erase(actorId) == 1;
                }
                 
                IActor* ActorFactory::placeActor(std::string actorId, World *world, const Vector2D location, const Vector2D scale, const Rotator rotation)
                {
                    CallbackMap::const_iterator it = this->callbacks.find(actorId);
                    
                    if (it == this->callbacks.end())
                    {
                        throw std::runtime_error("Unknown actor identefier");
                    }
                    
                    return (it->second)(world, location, scale, rotation);
                }


              Цитата Urich @
              А вообще такая регистрация плохая идея. Также как и статические переменные в либах.

              А какие проблемы могут возникнуть со статическими переменными?


              Как тогда лучше оформить регистрации в фабрике?
              Что-то вроде *.cpp-файла, в котором перечисляются все функции которые регистрируются ,а потом функцию, которая их всех регистрирует; и потом вызывать эту функцию где-нибудь в main?

              Цитата MyNameIsIgor @
              Что такое "одно место линковки"?

              Я думаю, имеется ввиду только один exe или dll, использующий библиотеку.
                Цитата WhyNot @
                А какие проблемы могут возникнуть со статическими переменными?

                Имелось ввиду возможность их двойной инициализации.

                Цитата WhyNot @
                Что-то вроде *.cpp-файла, в котором перечисляются все функции которые регистрируются ,а потом функцию, которая их всех регистрирует; и потом вызывать эту функцию где-нибудь в main?

                Ну как то так. Делать регистрацию явно, когда уже приложение инициализировано.

                пс. У линковщика есть параметр кажется /OPT:NOREF который запрещает выкидывать не используемый код.
                Если умеешь защищать программы, то умеешь их и ломать, но не наоборот.
                Документация как секс - лучше любая, чем никакой.
                  Цитата Urich @
                  пс. У линковщика есть параметр кажется /OPT:NOREF который запрещает выкидывать не используемый код.

                  Полезно.

                  Правда, я уже выделил регистрации в отдельный файл.

                  Всем спасибо.
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script Execution time: 0,1128 ]   [ 17 queries used ]   [ Generated: 15.12.17, 06:12 GMT ]