VS工程属性配置 /MDd /MLd /MTd之二(进阶)

什么MT版本的库?

链接选项预编译宏链接库说明
/MD _MT、_DLLMSVCRT.lib多线程、Release、DLL版本的运行时库
/MDd _DEBUG、_MT、_DLLMSVCRTD.lib多线程、Debug、DLL版本的运行时库
/MT _MTLIBCMT.lib多线程、Release版本的运行时库
/MTd _DEBUG、_MTLIBCMTD.lib多线程、Debug版本的运行时库

简单来说,MT版本库是静态链接运行时库,即编辑完成后不再以来运行时库(MSVCR60.dll或MSVCR71.dll)

Edit

为什么不建议使用

当你的工程没有DLL时,选择哪个链接库都可以。而当你的工程中包含DLL类型的工程时,这时就要小心下面两种情况:
  1. DLL 导出的函数中包含 STL库 对象的返回,如return std::string,或func(xxx,std::string& retVal);
    • 当出现这种情况时,绝对不要使用MT库
  2. DLL 导出的函数中不包含 STL库 对象
    • 当出现这种情况时,可以使用MT库

不建议使用 的根本原因在于 跨DLL 的内存管理。当使用MS的编译器时,C++的内存堆管理都是以 模块 为界的,
当跨越 模块 释放堆内存时,则会出现运行时异常(且异常不可避免)。当我们了解这个知识后,我们就明白为什么
会出现这么多的内存管理函数,如全局堆(GlobalXXX)和局部堆(mallocXXX)。

Edit

常见的错误举例

Edit

DLL导出函数,使用POD类型的参数和返回值(http://en.wikipedia.org/wiki/Plain_Old_Data_Structures)

DLL模块

char* foobar()
{
    return new char[100];
}
void foobar2(char** p)
{
    *p = new char[100];
}

EXE模块
int main()
{
     delete foobar();
     int* p = 0;
     foobar2(&p);
     delete p;
     return 0;
}

上面的情况的解决方案是在DLL提供专用的内存释放函数,确保在哪个模块分配内存,在哪个模块释放内存。
DLL模块

char* foobar()
{
    return new char[100];
}
void foobar2(char** p)
{
    *p = new char[100];
}
void releaseXX(char* p)
{
    delete[] p;
}

EXE模块
int main()
{
     char* p2 = foobar();
     releaseXX(p2);
     int* p = 0;
     foobar2(&p);
     releaseXX(p);
     return 0;
}

Edit

DLL导出函数,使用非POD类型的参数

DLL模块

void foobar(std::string& retVal);

EXE模块
int main()
{
    std::string val;
    foobar(val);
    return 0;
}

上面这种情况是最难发现,也是最难处理的情况。当使用MT版本时,val变量实际上是在foobar函数中分配内存,而在exe模块中析构(释放内存)。这就违反了堆的使用
规则(在哪个模块分配,须在哪个模块释放)。基本上无解,除非将函数声明改为POD形式的声明。而使用MD版本的运行时库时,则不会出现上述情况,所有的内存分配与释放都在运行时库DLL中进行,保证了堆管理的一致性。

因此,在使用MT版本时,一定要注意DLL函数的导出形式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值