[C++][MSVC][Error] __acrt_first_block == header

1 简介

当你使用 MSVC 编译器时遇到的 __acrt_first_block == header 错误通常与内存管理问题有关,特别是涉及到 C 运行时库 (CRT)。

这个错误通常是由于不同模块(如 DLL 和 EXE)在使用不同 CRT 时分配和释放内存的方式不匹配引起的。具体来说,当使用 /MTd 标志时,每个模块都会链接到其自己的 CRT 静态副本。这意味着每个模块都有自己的堆管理器,从而导致一个模块分配的内存在另一个模块中释放时发生冲突。

2 常见情况

发生这个错误一般是在调用动态库时出现,相当经典的场景就是动态库返回了 std::string 有关的数据类型(包括 std::vectorstd::string )。

std::string 是 STL 中定义的模板类,所以编译器在编译动态库时会将 std::string 实例化,在编译 exe 时也会将其实例化,也就是说有两套 std::string 实例代码分别在 exe 和 dll 中.

当 exe 调用函数,此时函数返回一个 std::string 对象给 exe 。显然,这个对象的内存是由 dll 分配的,但是 exe 并不能区分这个 std::string 对象的内存是不是自己的的 heap 中分配的。在 main 结束时会调用exe中实例化的std::string 析构函数代码来释放内存,然后就会抛出 __acrt_first_block == header 异常。

3 解决方法

为了避免这个问题,你应该确保所有模块使用相同的 CRT。例如,你可以通过在调试版本中使用 /MDd 标志和在发布版本中使用 /MD 标志来实现。这些标志会链接到共享的 CRT DLL,确保所有模块使用相同的堆管理器。这种方法有助于防止不同模块间内存分配和释放的冲突。

如果你需要跨模块混合分配和释放内存,考虑在 DLL 中提供用于分配和释放内存的函数。这样,分配和释放操作都由同一个堆管理器处理,避免冲突。

4 最简单粗暴的方法

以 CMake 为例,使用类似以下模版的 CMake 结构:

cmake 复制代码
# 设置策略CMP0091为NEW,新策略
if (POLICY CMP0091)
  cmake_policy(SET CMP0091 NEW)
endif (POLICY CMP0091)

# 声明一个工程
project(TestpyTest)

# 添加一个exe
add_executable(test test.cpp)

# 设置MT/MTd
set_property(TARGET test PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

然后使用 Release 版本进行编译即可

5 参考资料

相关推荐
qq_423233903 分钟前
C++与Python混合编程实战
开发语言·c++·算法
m0_7155753416 分钟前
分布式任务调度系统
开发语言·c++·算法
csbysj202033 分钟前
选择(Selectable)
开发语言
CSDN_RTKLIB37 分钟前
简化版unique_ptr说明其本质
c++
naruto_lnq37 分钟前
泛型编程与STL设计思想
开发语言·c++·算法
:Concerto1 小时前
JavaSE 注解
java·开发语言·sprint
m0_748708051 小时前
C++中的观察者模式实战
开发语言·c++·算法
时光找茬2 小时前
【瑞萨AI挑战赛-FPB-RA6E2】+ 从零开始:FPB-RA6E2 开箱测评与 e2 studio 环境配置
c++·单片机·边缘计算
qq_537562672 小时前
跨语言调用C++接口
开发语言·c++·算法
wjs20242 小时前
DOM CDATA
开发语言