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

Qt6+VS2019下自定义operator new类作信号槽参数编译报错

问题描述

定义包含自定义operator new、operator delete的基类BaseClass,MyClass公开继承自BaseClass,复现代码如下:

class BaseClass {
  void* operator new(size_t size);
  void operator delete(void* p);
};

class MyClass : public BaseClass {
public:
  MyClass(int);
};

将MyClass作为Qt信号与槽的传递参数时,Qt5环境下可正常编译运行,但在Visual Studio 2019环境使用Qt6时,会在QMetaType内部代码处触发编译错误,报错原因为无法匹配到MyClass的类专属placement new。
VS2019下的具体编译报错信息如下(已隐去特定路径与类名):

...QtCore\qmetatype.h(2313): error C2660: 'BaseClass::operator new': function does not take 3 arguments
: note: see declaration of 'BaseClass::operator new'
...QtCore\qmetatype.h(2310): note: while compiling class template member function 'QtPrivate::QMetaTypeInterface::CopyCtrFn QtPrivate::QMetaTypeForType<T>::getCopyCtr(void)'
        with
        [
            T=Ty
        ]
...QtCore\qmetatype.h(2370): note: see reference to class template instantiation 'QtPrivate::QMetaTypeForType<T>' being compiled
        with
        [
            T=Ty
        ]
...QtCore\qmetatype.h(2494): note: see reference to class template instantiation 'QtPrivate::QMetaTypeInterfaceWrapper<Ty>' being compiled
...QtCore\qmetatype.h(2537): note: see reference to function template instantiation 'const QtPrivate::QMetaTypeInterface *QtPrivate::qTryMetaTypeInterfaceForType<Unique,QtPrivate::TypeAndForceComplete<MyClass &,std::false_type>>(void)' being compiled
    with
    [
        Unique=qt_meta_stringdata_..._t
    ]
moc_xxx.cpp(286): note: see reference to variable template 'const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray<qt_meta_stringdata_ModelBrowser_t,QtPrivate::TypeAndForceComplete<ModelBrowser,std::integral_constant<bool,1> >,QtPrivate::TypeAndForceComplete<void,std::integral_constant<bool,0> >,QtPrivate::TypeAndForceComplete<void,std::integral_constant<bool,0> >,QtPrivate::TypeAndForceComplete<MyClass &,std::integral_constant<bool,0> >,QtPrivate::TypeAndForceComplete<void,std::integral_constant<bool,0> >,QtPrivate::TypeAndForceComplete<MyClass &,std::integral_constant<bool,0> >,QtPrivate::TypeAndForceComplete<void,std::integral_constant<bool,0> >,...[58]' being compiled

此前尝试为类添加通用类专属placement new(即void* operator new(size_t size, std::align_val_t, void*)),该写法虽然可在VS2019下通过编译,但不符合C++标准,在其他编译器下会编译失败。

根因分析
  • 触发编译错误的核心是C++的类域名称查找规则:当类内部声明了同名的operator new成员函数时,类域名称查找会优先匹配类内成员,不会自动搜索全局作用域下的其他operator new重载,除非显式将全局重载引入类作用域。
  • Qt6重构了元类型系统实现,在QMetaType的拷贝构造、对象构造逻辑中,会调用标准全局placement new(签名为void* operator new(std::size_t, void* ptr) noexcept,定义在<new>头文件中)在预分配内存上构造对象。由于基类自定义的单参数operator new隐藏了全局的placement new重载,重载决议时只能匹配到基类的单参数版本,参数数量不匹配就会触发编译错误。
  • Qt5的QMetaType实现未在元类型注册逻辑中通过类域查找调用placement new,因此不会触发该问题。
  • 手动添加带std::align_val_t参数的placement new属于编译器特定扩展,不符合C++标准对标准placement new的签名要求,跨编译器编译会出现签名不匹配问题,不具备可移植性。
符合C++标准的解决方案

优先选择通过using声明引入全局标准operator new重载的方案,完全符合C标准,无额外副作用,所有支持C11及以上版本的编译器均可正常编译:

  • 方案1(推荐,改动影响最小):在基类中引入全局operator new的所有重载,所有派生类自动生效。注意需要先引入<new>头文件确保全局placement new声明可见:
#include <new>

class BaseClass {
public:
  void* operator new(size_t size);
  void operator delete(void* p);
  // 将全局作用域所有operator new重载引入类域,参与重载决议
  using ::operator new;
};
  • 方案2:如果无法修改基类,可直接在派生类MyClass中添加同样的using声明,仅对当前派生类生效:
#include <new>

class MyClass : public BaseClass {
public:
  MyClass(int);
  // 引入全局operator new重载
  using ::operator new;
};
  • 方案3:如果自定义的类专属operator new不需要对派生类生效,可将基类的operator new声明为private,或在派生类中重写默认operator new逻辑,但该方案改动影响范围更大,仅在明确业务逻辑需要时使用。

内容的提问来源于stack exchange,提问作者Hans Olsson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:21:35