Есть менеджер шрифтов, реализованный как синглтон Мейерса. В нем используется QFontDatabase что бы подгрузить шрифты с диска (точнее, из ресурсов), операция проходит успешно, вызов вида
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-Bold.otf")
возвращает id загруженного шрифта, он != -1.
В деструкторе вызывается QFontDatabase::removeAllApplicationFonts(), и в нём приложение падает. Если этот вызов закомментировать - всё в порядке.
Помогите понять, в чем проблема.
Да, если вызов removeAllApplicationFonts переместить из в конструктор, сразу же после загрузки шрифтов - проблема исчезает, даже если вызов в деструкторе оставить.
C++ (Qt)
#define SINGLETON_COPY_CREATE_RESTRICT(ClassName) \
ClassName() {} \
ClassName(const ClassName&) {} \
ClassName& operator=(const ClassName&) {return *(new ClassName());} \
friend class Singleton <ClassName>;
#define SINGLETON_COPY_RESTRICT(ClassName) ClassName(const ClassName&) {} \
ClassName& operator=(const ClassName&) {return *(new ClassName());} \
friend class Singleton <ClassName>;
template<class T> class Singleton //Single-threaded Meyers singleton
{
protected:
Singleton() {}
Singleton(const Singleton&) {}
Singleton& operator=(const Singleton&) {}
virtual ~Singleton() {}
public:
static T& Instance()
{
static T object;
return object;
}
};
C++ (Qt)
class FontManager : public Singleton<FontManager>
{
SINGLETON_COPY_RESTRICT(FontManager)
FontManager();
public:
~FontManager();
};
C++ (Qt)
FontManager::FontManager(void)
{
int id = -1;
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-Bold.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-BoldCond.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-BoldIt.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-Cond.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-It.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-Regular.otf");
id = QFontDatabase::addApplicationFont(":/fonts/MyriadPro-CondIt.otf");
}
FontManager::~FontManager()
{
QFontDatabase::removeAllApplicationFonts(); //AARRRRRGHHHH!
}
Сейчас нет времени разбираться досконально, но есть предположение:
Вопрос в порядке вызова деструкторов для статических объектов. Возможно в момент вызова деструктора FontManager и соответственно метода QFontDatabase::removeAllApplicationFonts() внутренний структуры QFontDatabase уже разрушены.
То, что проблема исчезает если нет ни одного загруженного фонта, то это возможно из-за следующего кода в removeAllApplicationFonts():
C++ (Qt)
QMutexLocker locker(fontDatabaseMutex());
QFontDatabasePrivate *db = privateDb();
if (db->applicationFonts.isEmpty()) // !!! выходим без выгрузки фонтов
return false;
// Если фонты есть - думаю падает где-то здесь...
FcConfigAppFontClear(0);
db->applicationFonts.clear();
db->invalidate(); // <<< Здесь очищается кэш фонтов (думаю здесь)
return true;