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

在std::unique_ptr的删除器中是否需要使用__stdcall?

为何MSVC编译32位和64位时std::unique_ptr函数指针行为不同?

尝试用std::unique_ptr管理带__stdcall调用约定的函数对,代码如下:

#include <memory>

int* __stdcall construct(){ return new int{5}; }
void __stdcall destruct(int* v){ delete v; }

int main() {
    using Ptr = std::unique_ptr<int, void(&)(int*)>;
    Ptr v(construct(), destruct);
}

使用MSVC 19.33编译64位二进制可正常运行,但编译32位时报错:

example.cpp
<source>(8): error C2660: 'std::unique_ptr<int,void (__cdecl &)(int *)>::unique_ptr': function does not take 2 arguments
C:/data/msvc/14.33.31631/include\memory(3291): note: see declaration of 'std::unique_ptr<int,void (__cdecl &)(int *)>::unique_ptr'
Compiler returned: 2

若在std::unique_ptr的删除器模板参数中显式指定__stdcall(即std::unique_ptr<int, void(__stdcall&)(int*)>),则32位与64位编译均可正常运行。


原因分析

这不是编译器bug,而是32位和64位Windows平台对调用约定的处理差异导致:

  • 64位Windows平台:仅存在一种通用调用约定(微软定义的x64调用约定,等价于__fastcall),__stdcall、__cdecl等关键字在64位编译时会被忽略,所有函数指针统一使用该调用约定。因此void(&)(int*)会自动匹配__stdcall函数的类型,不会出现类型不匹配问题。
  • 32位Windows平台:__stdcall和__cdecl是两种完全不同的调用约定,函数指针类型会严格区分调用约定。当你写void(&)(int*)时,MSVC默认将其推导为__cdecl的函数引用类型,但你的destruct函数是__stdcall类型,两者类型不兼容。而std::unique_ptr没有对应这种类型不匹配参数的构造函数重载,因此触发编译错误。

显式指定__stdcall后,删除器的引用类型与实际函数的调用约定完全一致,32位编译时就能正确匹配构造函数重载。

内容的提问来源于stack exchange,提问作者Benjamin Buch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:07:57