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

带__declspec(dllexport)的C++代码仅在MSVC编译失败的原因咨询

问题:MSVC导出含std::unique_ptr的结构体时编译失败

代码片段

#include<memory>
#include<unordered_map>

struct
__declspec(dllexport)
Foo {
    std::unordered_map<const int*, std::unique_ptr<int>> foo;
};

Foo foo();

编译错误信息

C:/data/msvc/14.39.33321-Pre/include\list(1299): error C2679: binary '=': no operator found which takes a right-hand operand of type 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' (or there is no acceptable conversion)
C:/data/msvc/14.39.33321-Pre/include\utility(315): note: could be 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)': cannot convert argument 2 from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty> &'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: Reason: cannot convert from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty>'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]

... 完整错误信息详见编译示例

疑问

已知问题根源是std::unique_ptr不可拷贝,但不解为何仅在Windows平台添加__declspec(dllexport)时,才要求该类型具备可拷贝性?

代码库中__declspec(dllexport)是宏,Linux下会展开为__attribute__((visibility("default"))),此时代码可正常编译。


原因与解决方案

核心原因

MSVC处理__declspec(dllexport)标记的类时,会强制生成该类的完整导出元数据,包括对类的所有成员(这里是std::unordered_map)的拷贝构造/赋值操作的合法性检查——哪怕你的代码并没有显式调用这些操作。

std::unordered_map的内部实现依赖节点链表结构,MSVC生成导出代码时会触发对std::pair<const int*, std::unique_ptr<int>>的赋值操作检查。由于std::unique_ptr禁用了拷贝赋值,导致对应的std::pair拷贝赋值也不可用,最终触发编译错误。

为何Linux下无问题?

GCC/Clang处理__attribute__((visibility("default")))时,不会像MSVC那样强制检查类的所有隐式生成的特殊成员函数。Linux动态链接机制更宽松,只要代码中实际调用的操作合法,就不会触发这类检查——你的代码里并没有实际拷贝Foo或其内部的unordered_map,因此编译通过。

解决方案

  1. 移除不必要的导出标记:如果Foo不需要跨DLL边界访问,直接去掉__declspec(dllexport)。
  2. 显式删除拷贝操作:在Foo中显式删除拷贝构造和拷贝赋值,阻止MSVC尝试生成这些操作的导出代码:
    struct __declspec(dllexport) Foo {
        std::unordered_map<const int*, std::unique_ptr<int>> foo;
        
        // 显式删除拷贝操作
        Foo(const Foo&) = delete;
        Foo& operator=(const Foo&) = delete;
    };
    
  3. 改用指针跨DLL传递:如果需要跨DLL暴露Foo实例,导出返回std::unique_ptr<Foo>的工厂函数,而非直接导出Foo类的拷贝操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:05:18