什么MT版本的库?
链接选项 | 预编译宏 | 链接库 | 说明 |
/MD | _MT、_DLL | MSVCRT.lib | 多线程、Release、DLL版本的运行时库 |
---|---|---|---|
/MDd | _DEBUG、_MT、_DLL | MSVCRTD.lib | 多线程、Debug、DLL版本的运行时库 |
/MT | _MT | LIBCMT.lib | 多线程、Release版本的运行时库 |
/MTd | _DEBUG、_MT | LIBCMTD.lib | 多线程、Debug版本的运行时库 |
简单来说,MT版本库是静态链接运行时库,即编辑完成后不再以来运行时库(MSVCR60.dll或MSVCR71.dll)
为什么不建议使用
当你的工程没有DLL时,选择哪个链接库都可以。而当你的工程中包含DLL类型的工程时,这时就要小心下面两种情况:- DLL 导出的函数中包含 STL库 对象的返回,如return std::string,或func(xxx,std::string& retVal);
- 当出现这种情况时,绝对不要使用MT库
- DLL 导出的函数中不包含 STL库 对象
- 当出现这种情况时,可以使用MT库
不建议使用 的根本原因在于 跨DLL 的内存管理。当使用MS的编译器时,C++的内存堆管理都是以 模块 为界的,
当跨越 模块 释放堆内存时,则会出现运行时异常(且异常不可避免)。当我们了解这个知识后,我们就明白为什么
会出现这么多的内存管理函数,如全局堆(GlobalXXX)和局部堆(mallocXXX)。
常见的错误举例
DLL导出函数,使用POD类型的参数和返回值(http://en.wikipedia.org/wiki/Plain_Old_Data_Structures)
DLL模块
EXE模块
上面的情况的解决方案是在DLL提供专用的内存释放函数,确保在哪个模块分配内存,在哪个模块释放内存。
DLL模块
EXE模块
DLL导出函数,使用非POD类型的参数
DLL模块
EXE模块
上面这种情况是最难发现,也是最难处理的情况。当使用MT版本时,val变量实际上是在foobar函数中分配内存,而在exe模块中析构(释放内存)。这就违反了堆的使用
规则(在哪个模块分配,须在哪个模块释放)。基本上无解,除非将函数声明改为POD形式的声明。而使用MD版本的运行时库时,则不会出现上述情况,所有的内存分配与释放都在运行时库DLL中进行,保证了堆管理的一致性。
因此,在使用MT版本时,一定要注意DLL函数的导出形式。