C++ C++;全局变量在通过静态库链接时未初始化,但在使用源代码编译时正常
我创建了一个系统,该系统基于全局实例的构造函数自动将函数对象(functor)注册到映射中 在定义函子的每个cpp文件中,都有注册器类实例的全局实例,用于将函子注册到singletonC++ C++;全局变量在通过静态库链接时未初始化,但在使用源代码编译时正常,c++,initialization,global-variables,static-libraries,static-linking,C++,Initialization,Global Variables,Static Libraries,Static Linking,我创建了一个系统,该系统基于全局实例的构造函数自动将函数对象(functor)注册到映射中 在定义函子的每个cpp文件中,都有注册器类实例的全局实例,用于将函子注册到singletonstd::map对象 这是注册商类别的定义: template < typename map_type, typename handler_type > struct registrar { registrar ( map_type&am
std::map
对象
这是注册商类别的定义:
template
<
typename map_type,
typename handler_type
>
struct registrar
{
registrar
(
map_type& map_object,
boost::uint16_t cmd_code,
const handler_type& handler
)
{
map_object.insert(std::pair<boost::uint16_t, handler_type>(cmd_code, handler));
}
};
模板
<
类型名称映射类型,
类型名称处理程序\u类型
>
结构注册器
{
登记员
(
映射类型和映射对象,
boost::uint16\u t cmd\u代码,
常量处理程序类型和处理程序
)
{
map_object.insert(std::pair(cmd_代码,handler));
}
};
在每个.cpp文件中。全局实例的定义如下:
namespace one_way
{
static registrar <in_out_map_type, handler>
post_receiver(in_out_map_type::instance(), command, handlers());
}
名称空间单向
{
静态注册器
post_receiver(in_out_map_type::instance(),command,handlers());
}
如果我将所有cpp与main.cpp一起编译,那么所有这些都可以正常工作。但是,如果我将cpp文件编译到一个静态库中,并将其链接到main.cpp
,注册将不起作用
我在Windows和Ubuntu11.10上测试了VC10和GCC4.61。两者都失败了
我发现了,但OP并没有说他是否解决了这个问题
我遗漏了什么吗
编辑
感谢所有回复,包括评论 每一个回答都确实帮助我对这种方法进行了更多的思考和深入的研究。经过所有的研究和试验,我最终放弃了依靠全局/静态变量跨二进制边界进行自我注册的想法,因为没有可移植的方法来保证它能工作
我的最后一个方法是将注册保持在一个二进制文件内。我相信库中的对象文件没有链接。看看微软是如何处理acrtused符号的(搜索不区分大小写,我不记得大小写,而且这台机器上没有MSVC) 一旦你知道它们是如何处理acrtused的,对你的全局变量做同样的事情,迫使它链接起来 如果我找到答案,将会更新 这里有几种可能的方法,可以强制链接并以某种强制顺序初始化 寻找一个GCC答案
查找MSVC10。对于android NDK工作,任何受此问题影响的静态库都应添加到本地_total_static_LIBRARIES变量中——然后使用
-Wl,--total archive
标志引用它们,并且不会被剥离
MSVC的详细答案:
转换单元中的静态变量在转换单元中的任何常规代码之前初始化
翻译单元执行。在实践中,当包含
已加载可执行或动态库。调用\c main()或调用
LoadLibrary()/dlopen()
完成后,所有静态变量都将被初始化
该问题的描述如下:
声明中全局函数或静态方法的构造函数和赋值
不创建引用,也不会阻止/OPT:REF消除。这些药物的副作用
当不存在对数据的其他引用时,不应依赖代码
可以方便地将多个翻译单元中的目标代码放在单个翻译单元中
文件,一个静态库,通常用\c.lib或\c.a后缀命名。MSVC链接器没有
对静态库进行依赖性分析,不包括未引用的代码
由包括实体提供
使用静态变量声明并导致注册的常见模式
在这种情况下,工厂对象可能会失败——MSVC链接器将静态对象视为
不可接近的,并将其从结果中删除
解决方案
一个有用的谷歌搜索:
一种解决方案是在包含的实体上设置/OPT:NOREF
链接器标志。然而,
这是一个全有或全无设置,要求所有包含的库都可以完全链接
如果文件中包含static的内容被
包含实体,然后根据语言规则,必须保留静态本身
最基本的方法是在文件中放置一个伪函数,并从
被认为可以到达的地方
另一种方法是使用/INCLUDE
链接器标志引用问题文件中的实体。
假设一个名为DummyForLinkProblem的实体,这可以在包含实体的源中完成:
#pragma comment(linker, "/include:DummyForLinkProblem")
当前受此问题影响的ZooLib实体是
ZFile_Win.cpp、ZGRgnRep_HRGN.cpp、ZNet_Internet_WinSock.cpp、ZStreamRWCon_SSL_Win.cpp、,
ZTextCoder_Win.cpp和ZUnicode_规范化_Win.cpp
我们在相应的头文件中包含ZCompat_MSVCStaticLib.h,并在每个
ZMACRO\u MSVCStaticLib\u参考(ModifiedFileName)
。在cpp文件中,我们放置了一个
ZMACRO\u MSVCStaticLib\u cpp(ModifiedFileName)
。ModifiedFileName
通常是
删除前导Z和文件扩展名的文件名,样式与
用于ZCONFIG\u API\u XXX
宏
为了确保您的可执行文件或库不会剥离这些实体,只需#包括
包含实体中已知引用代码的相应头文件。这将
导致一个不执行的引用发生,事情将按预期进行。您不会显示如何为已注册的函数调用注册器。另外,“全局实例”(
handlers()
而不是handler()
)中是否有输入错误?除非我遗漏了什么,它定义了一个函数,而不是一个全局变量。所以,在我看来,这张照片中缺少了一些连接点