Собственно есть код в духе: (упрощенно) Код (Text): class CBasePacket; ... class CPacketFactory { static long RegisterPacket(long type, CreationRoutine cr); ... } ... class CCallUsermodePacket: CBasePacket { ... static volatile long s_type; static CBasePacket* CreateNew(); .... } __declspec(selectany) long CCallUsermodePacket::s_type = CPacketFactory::RegisterPacket(eCallUserMode, CreateNew); ... т.е. фабрика классов с "саморегистрацией", так вот в релизе нет ни s_type, ни RegisterPacket, а соответственно и автоматической регистрации.. #pragma optimize не помогает, у кого-нибудь есть идеи, как побороть?
А сам по себе класс "CCallUsermodePacket" используется? Возможно ли, что в полной версии "CCallUsermodePacket" – шаблонный класс? "volatile" для "s_type" не нужен – не поможет. Также не видим необходимости в __declspec(selectany). В крайнем случае можно попробовать сделать ссылку на "s_type" в каком-нибудь используемом методе: volatile long* stype_hack = &CCallUsermodePacket::s_type;
_DEN_, Sol_Ksacap Если убрать __declspec(selectany), то действительно все работает, но фишка в том что я привел код хидера, который будет инклюдиться в несколько сишников, а убирать __declspec(selectany) long CCallUsermodePacket::s_type = CPacketFactory::RegisterPacket(eCallUserMode, CreateNew); в соответствующий сишнег -- плохо, т.к. суть фишки в том, что новые наследники CBasePacket достаточно объявить в этом хидере + добавить в конце Код (Text): class CCallUsermodePacket ... DECLARE_PACKET (CCallUsermodePacket); }; REGISTER_PACKET(CCallUsermodePacket, eCallUsermode); т.е. добавить соответствующие макросы -- и все, мы можем юзать дальше код типа Код (Text): CTestComm com; CPacketBase* pPacket = CPacketFactory::ReadPacket(com); т.е. мы вычитываем из "того, что нам дадут"(пайп, порт лпц, сокет, кусок разделяемой памяти и т.д.) Код (Text): template<class TCommunicator> static CPacketBase* ReadPacket(TCommunicator& ctr) { PacketType type; _S_0 (ctr.Read(&type, sizeof(type))); std::auto_ptr<CPacketBase> packet((s_creationRoutines[type])()); if (packet.get()) { _S_0 (packet->FillWithData(ctr)); } return packet.release(); } тип, а потом создаем объект, на основе вычитанных данных. Несколько месяцев назад на работе я сталкивался с подобной задачей, только там были пайпы, и я так все и писал, но тестил все на отладочной версии, поэтому в последний момент всплыл такой вод баг, и пришлось срочно все править -- я просто сделал глобальную функцию RegisterPacketTypes, в которую добавлял макрос для каждого типа, и вызывал ее из мэйна/длл-мэйна, а сейчас речь идет о том, что не к спеху, делается пока для себя, и поэтому хочется получить максимальное количество удовольствия от красивого и правильного кода))
Sol_Ksacap /add volatile -- это я на всякий случай, т.к по идее и без него должно быть ок(по мои представлениям)) так делал, не помогает
Velheart #pragma comment(linker, "/include:?s_type@CCallUsermodePacket@@0JC") Проверь на всякий случай декорированное имя.
green Ога, так работает, только не могу в макрос включить эту строчку: Код (Text): #define REGISTER_PACKET(cls, type) \ __declspec(selectany) PacketType cls::s_type = CPacketFactory::RegisterPacket(type, cls::CreateNew); \ #pragma comment(linker, "/include:?s_type@##cls##@@2W4PacketType@@C"); не компилится, но можно че-нить попридумывать может быть)
Velheart Код (Text): #define REGISTER_PACKET(cls, type) \ __declspec(selectany) PacketType cls::s_type = CPacketFactory::RegisterPacket(type, cls::CreateNew); \ __pragma(comment(linker, "/include:?s_type@##cls##@@2W4PacketType@@C"))
nop_ Случайно сейчас наткнулся опять на эту тему =) Имхо именно так и есть, т.к. важно не то, что скрыто за макросами (красота будет потом, а в этот хэдер никто никогда не заглянет), а то насколько удобно потом это будет расширять и поддерживать, макросы будут написаны один раз, а в каждый новый класс, по аналогии с остальными будет добавляться одна строчка с функционалом а-ля "пыщ, сделай чтоб все было" + код будет хорошо читаем и не загромажден лишним, необходимо дублируемым но очень похожим кодом, так что улыбка не совсем к месту =)
Сказав "красота будет потом", ты согласился с тем, что к приведенному коду не применимы такие характеристики как "красивый и правильный" =) По существу - здесь проблема из-за этого: "в каждый новый класс, по аналогии с остальными будет добавляться одна строчка ". В месте определения класса, при таком использовании, появляется зависимость от CPacketFactory со всеми вытекающими последствиями - клиенты (те самые классы) становятся не самодостаточными, изменение интерфейса CPacketFactory влечет за собой перекомпиляцию всех зависимых классов и т.д. Впрочем, насколько это существенно - решать тебе.
Вариация на тему данного решения: http://rsdn.ru/forum/cpp.applied/3570438.1.aspx Основой для решения послужил материал этого топика.