我有下一个情况:我需要在独立静态库中创建小部件,然后将其与最终应用程序链接(visual c ++ 9.0,qt 4.5)。 此静态窗口小部件库包含一些资源(图标),并包含多个.cpp文件(每个文件包含独立窗口小部件)。据我所知,我必须初始化qt资源系统,如果我在静态库中使用它们(资源),调用“Q_INIT_RESOURCE(resource_file_name)”。我用下一个代码(在静态库中的每个.cpp文件中)解决了这个问题:
#include <QAbstractButton>
namespace {
struct StaticLibInitializer
{
StaticLibInitializer()
{
Q_INIT_RESOURCE(qtwidgets_custom_resources);
}
};
StaticLibInitializer staticLibInitializer;
}
// ... widget code ....
我没有使用第一种方法,而是使用初始化代码在静态库项目中创建了单独的init.cpp文件(以避免在每个.cpp文件中包含初始化代码),但这不起作用。
为什么这不起作用?
这种使用StaticLibInitializer的方法在各种编译器和平台之间是否安全且可移植?
答案 0 :(得分:11)
它没有用,因为你设法被static initialization order fiasco击中了。
您无法将初始化静态对象的代码移动到使用这些静态对象的翻译单元(您可以将其作为源文件读取)之外。不是你这样做的方式。如果要使用用于初始化这些静态对象的方案,而不是仅将声明移动到init.hpp标头,而是在每个使用静态对象的文件中保留instatiations StaticLibInitializer staticLibInitializer;
。
以上建议假设每个小部件仅使用自己的资源。如果您遇到另一个小部件使用一个小部件资源的情况,则会再次遇到静态初始化顺序fiasco。您可以使用此类代码来管理这种情况
StaticLibInitializer
{
void initialize()
{
static Q_INIT_RESOURCE(qtwidgets_custom_resources);
}
StaticLibInitializer()
{
initialize();
}
}
确保StaticLibInitializer的多次实例化只会初始化给定资源一次,然后为要在给定转换单元中使用的每个资源实例化StaticLibInitializer。
答案 1 :(得分:7)
Q_INIT_RESOURCE宏不能在命名空间中使用。
让我引用qt手册:“注意:这个宏不能在名称空间中使用。它应该从main()调用”。如果不可能,它甚至会为您提供一个如何正确执行的示例:
inline void initMyResource() { Q_INIT_RESOURCE(myapp); }
namespace MyNamespace
{
...
void myFunction()
{
initMyResource();
}
}
如果您以未指定的方式使用它,请查看自己为什么以及如何失败或失败。相关代码在QtCore中。