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

相关推荐
ytttr8734 小时前
隐马尔可夫模型(HMM)MATLAB实现范例
开发语言·算法·matlab
天远Date Lab4 小时前
Python实战:对接天远数据手机号码归属地API,实现精准用户分群与本地化运营
大数据·开发语言·python
listhi5204 小时前
基于Gabor纹理特征与K-means聚类的图像分割(Matlab实现)
开发语言·matlab
qq_433776425 小时前
【无标题】
开发语言·php
会周易的程序员5 小时前
多模态AI 基于工业级编译技术的PLC数据结构解析与映射工具
数据结构·c++·人工智能·单例模式·信息可视化·架构
Davina_yu5 小时前
Windows 下升级 R 语言至最新版
开发语言·windows·r语言
阿珊和她的猫5 小时前
IIFE:JavaScript 中的立即调用函数表达式
开发语言·javascript·状态模式
listhi5206 小时前
卷积码编码和维特比译码的MATLAB仿真程序
开发语言·matlab
yuan199976 小时前
基于主成分分析(PCA)的故障诊断MATLAB仿真
开发语言·matlab
J_liaty6 小时前
Java版本演进:从JDK 8到JDK 21的特性革命与对比分析
java·开发语言·jdk