如何为模板化QSharedPointer编写自定义删除器并解决编译错误
问题背景
想要实现一个模板化包装类,通过QSharedPointer管理被包装类的生命周期(无法修改被包装类),同时自定义删除器来验证对象释放时机。但编译时出现如下错误:
Error C2664 'void (T *)': cannot convert argument 1 from 'T *' to 'T *' testshared Qt\6.4.1\msvc2019_64\include\QtCore\qsharedpointer_impl.h 79
相关代码:
#include <QtCore/QCoreApplication> #include <QSharedPointer> class A { public: virtual ~A() { qInfo() << "Deleting an A"; } void doA(void) { qInfo() << "Doing A thing"; } }; class B : public A {}; class SharedA { public: QSharedPointer<A> m_spA; }; template<class T> class SharedB :public SharedA { public: static void DeleteB(T* p) { qInfo() << "deleting shared"; delete p; } SharedB() { m_pB = new B; A* pA = dynamic_cast<A*>(m_pB); m_spA = QSharedPointer<A>(pA, DeleteB); } B* m_pB; }; void lifespan() { SharedB<B> bThing; bThing.m_pB->doA(); } int main(int argc, char* argv[]) { QCoreApplication a(argc, argv); lifespan(); }
错误原因
创建QSharedPointer<A>时,传入的静态删除器SharedB<B>::DeleteB签名是void(B*),但QSharedPointer要求的删除器签名是void(A*)。虽然B可以隐式转换为A,但函数指针类型匹配时编译器不会自动做这个转换,导致类型不兼容报错。
修复方案
方案一:修改删除器参数类型为A*
调整静态删除器的参数为A*,匹配QSharedPointer的要求,内部再转换回T*类型:
template<class T> class SharedB :public SharedA { public: static void DeleteB(A* p) { qInfo() << "deleting shared"; // 安全转换为T*,因为实际指向的是B对象 delete static_cast<T*>(p); } SharedB() { m_pB = new B; // B*可隐式转换为A*,无需dynamic_cast m_spA = QSharedPointer<A>(m_pB, &SharedB<T>::DeleteB); } B* m_pB; };
方案二:使用Lambda作为删除器
Lambda可以自动适配类型转换,写法更简洁灵活:
template<class T> class SharedB :public SharedA { public: SharedB() { m_pB = new B; m_spA = QSharedPointer<A>(m_pB, [](A* p) { qInfo() << "deleting shared"; delete static_cast<T*>(p); }); } B* m_pB; };
额外优化
- 无需用
dynamic_cast将B转为A,子类指针可隐式转换为父类指针,dynamic_cast在此处多余。 - 成员变量
m_pB可考虑移除,需要访问B类型时,可通过static_cast<B*>(m_spA.data())获取(需确保对象确实是B类型)。
内容的提问来源于stack exchange,提问作者Techniquab
相关产品推荐
相关产品推荐

