[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 参考资料

相关推荐
樱花树下的数学喵2 小时前
手写简易 STL string|C++ 字符串底层实现
开发语言·c++
AI吃大瓜2 小时前
指针压力表读数3:C/C++实现指针压力表读数(可实时检测)
c++·指针读数·指针压力表·压力表自动读数·压力表读数
-银雾鸢尾-2 小时前
两数之和-C++实现
c++·算法
j7~2 小时前
【动态规划算法专题】动态规划五部曲实战:泰波那契数、三步问题、最小花费爬楼梯
c++·算法·动态规划·数据结构与算法
jimy12 小时前
C++ 报错的 qualifiers 的意思
开发语言·c++
揽星河..3 小时前
【C++】类和对象
c++·算法
D e re k ZH3 小时前
C++ 并发、未定义行为与工程化难点(No 3)
数据结构·c++·算法·面试
不积跬步无以至千里mmbb264 小时前
rust_analysis
开发语言·后端·rust
暴力求解4 小时前
C++ ---继承(二)
开发语言·c++·算法
陈飞EXCEL4 小时前
北京杰飞 IT 旗下妙码生花少儿Python编程上线两大学习系统
开发语言·python·学习