You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为模板化QSharedPointer编写自定义删除器并解决编译错误

QSharedPointer自定义删除器编译错误C2664解决

问题背景

想要实现一个模板化包装类,通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:37:17