У меня проблема, я не уверен, как решить ..
У нас есть общий пул объектов. Когда объект запрашивается, пул возвращается QSharedPointer
к первому доступному экземпляру, с указанием пользовательского Deleter. Удалитель просто возвращает объект в пул, когда QSharedPointer
Счетчик экземпляров равен 0.
Все отлично работает для простых объектов. Это также отлично работает для QObject
преемники, при компиляции в Qt 5.
Однако, если скомпилировано в Qt 4.6 — начинаются проблемы: когда один и тот же объект запрашивается второй раз — приложение завершает работу с ошибкой:
«QSharedPointer: указатель ххх уже имеет подсчет ссылок»
Я написал простой тест:
QObject* obj = new QObject();
QSharedPointer<QObject> p(obj, deleter); // deleter here does nothing
p.clear();
QSharedPointer<QObject> p2(obj, deleter); // this crashes the app
И, конечно же, это терпит неудачу при компиляции в Qt 4.6. Опять же: отлично работает в QT 5.x.
Изучив исходный код Qt, он обнаружил, что 4.6 инициализирует внутренний счетчик ссылок в QObject
когда это QObject
используется как QSharedPointer
параметр. Это сделано для того, чтобы никакие два умных указателя не могли указывать на один и тот же объект, и он будет сброшен только в деструкторе.
Qt5 не проверяет значение счетчика реф, когда QObject
Экземпляр обернут в смарт-указатель, таким образом, он работает.
Кто-нибудь знает обходной путь для более старой версии Qt? Есть ли способ полностью сбросить внутреннее состояние Qt, включая счетчик ссылок? Любые намеки приветствуются.
Предполагая, что у вас есть пул, чтобы избежать выделения и освобождения памяти, вы должны выделить память только один раз, а затем явно вызывать конструктор и деструктор, когда вы запрашиваете и возвращаете «новый» объект.
/* deleter calls destructor explicitly when return object to pool */
void deleter(QObject *object) {
object->~QObject();
mark_as_available();
}
/* allocate (one object) pool memory without calling constructor*/
QObject *object = ::operator new(sizeof(QObject));
/* request object - calling constructor on already allocated memory */
mark_as_taken();
return QSharedPointer(::new (object) QObject, &deleter);
/* deallocate pool memory without calling destructor */
::operator delete(object);
вам разрешено создавать только один раз QSharedPointer
от QObject
последний вам нужно будет скопировать существующий QSharedPointer
пример
в соответствии с Qt 4 и 5 документы:
QSharedPointer удалит указатель он удерживается, когда выходит из области видимости, при условии, что другие объекты QSharedPointer не ссылаются на него.
так что ваши образцы поведения, как показано ниже:
QObject* obj = new QObject();
QSharedPointer<QObject> p(obj, deleter); // deleter here does attach to "obj"p.clear(); //this does cause delete of "obj"QSharedPointer<QObject> p2(obj, deleter); // using deleted pointer will cause crash (if you are lucky XD)
с помощью QWeakPointer не удалит QObject
и утверждение:
«QSharedPointer: указатель ххх уже имеет подсчет ссылок»
чтобы убедиться, что вы не создали несколько случайных удалений (что сделало мой день безопасным, я использовал QSharedPointer
но имел ввиду QWeakPointer
) но иногда это мешает.