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

相关推荐
码匠许师傅7 小时前
【C++ 面试真题】C++ 的 const 和 constexpr 有什么区别?
c++·面试
BUG研究员_9 小时前
Runnable与LCEL
开发语言·人工智能·python
果果燕10 小时前
实习笔记(一):NFS、Samba、VNC、Git、CMake、systemd、内核、交叉编译
linux·arm开发·c++·笔记·git
牛艺翔10 小时前
C++基础
开发语言·c++
键盘会跳舞10 小时前
C++ :容器适配器stack源码级拆解
开发语言·c++··stack·先进后出
美味蛋炒饭.10 小时前
Git 版本控制(下)
开发语言·git·学习·总结·后端开发
我星期八休息11 小时前
网络编程—网络层
开发语言·前端·网络·人工智能·智能路由器
问商十三载11 小时前
RAG 检索效果差怎么排查?2026 五层诊断法完整指南
开发语言·人工智能·windows·python·算法
不负岁月无痕11 小时前
简单理解操作系统结构
java·linux·c语言·开发语言·c++·面试
余额瞒着我当琳11 小时前
C++模板初阶与STL初探
android·java·c++