Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.168] |
|
Сообщ.
#1
,
|
|
|
Компилятор: идущий по стандарту с VS2012
ОС: Windows Нашёл для себя интересную особенность, связанную с компоновщиком. Если в статической библиотеке есть объектные файлы на которые нет ссылок, то эти объектные файлы не компонуются с программой. Соответственно, не инициализируются любые статические объекты в этом файле. С одной стороны, всё логично. Но вот например, у меня есть код регистрирующий конструкторы классов в фабрике: #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 вручную, то объектный файл подключается, происходит регистрация, и остальные объекты этого класса нормально создаются. Пока не вижу хорошего решения этой проблемы: Что можете посоветовать в данной ситуации? |
Сообщ.
#2
,
|
|
|
WhyNot
Код фабрики покажи. А вообще такая регистрация плохая идея. Также как и статические переменные в либах. |
Сообщ.
#3
,
|
|
|
Цитата Urich @ Код фабрики покажи Код фабрики здесь не при чём. Компоновщик выбрасывает "неиспользуемый" код, вот и всё - проблема известная. Цитата Urich @ А вообще такая регистрация плохая идея. Идея хорошая, способствующая слабой связности. Но компоновщик её вечно портит. Меня тоже волнует вопрос топикстартера. Цитата Urich @ Также как и статические переменные в либах. С чего бы? |
Сообщ.
#4
,
|
|
|
Цитата MyNameIsIgor @ Идея хорошая, способствующая слабой связности. Но компоновщик её вечно портит. Я с этой хорошей идей намучился. Пока у тебя в проекте одно место линковки, пока не используешь менеджеры памяти отличные от рантаймоских. Пока это только твой проект, у тебя все хорошо. |
Сообщ.
#5
,
|
|
|
Цитата Urich @ Пока у тебя в проекте одно место линковки Что такое "одно место линковки"? Цитата Urich @ пока не используешь менеджеры памяти отличные от рантаймоских Не вижу проблем. Цитата Urich @ Пока это только твой проект, у тебя все хорошо. Как раз IoC всегда помогало делать проект "не только моим". |
Сообщ.
#6
,
|
|
|
Цитата Urich @ Код фабрики покажи. ActorFactory.h #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 #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, использующий библиотеку. |
Сообщ.
#7
,
|
|
|
Цитата WhyNot @ А какие проблемы могут возникнуть со статическими переменными? Имелось ввиду возможность их двойной инициализации. Цитата WhyNot @ Что-то вроде *.cpp-файла, в котором перечисляются все функции которые регистрируются ,а потом функцию, которая их всех регистрирует; и потом вызывать эту функцию где-нибудь в main? Ну как то так. Делать регистрацию явно, когда уже приложение инициализировано. пс. У линковщика есть параметр кажется /OPT:NOREF который запрещает выкидывать не используемый код. |
Сообщ.
#8
,
|
|
|
Цитата Urich @ пс. У линковщика есть параметр кажется /OPT:NOREF который запрещает выкидывать не используемый код. Полезно. Правда, я уже выделил регистрации в отдельный файл. Всем спасибо. |