C++ string warning C4251

有一次在项目中用到C++的string (以前一直是用C的,对于C++的一些特性不是很了解),记录下遇到的一些问题。

 

整个项目有一个DLL和一个exe程序,DLL的类成员里面使用的一些string(主要是用它的find 、+的功能),在编译的时候有warning C4251的警告,F5运行程序没有什么问题,但是直接打开exe的时候就崩溃了,怀疑和这个C4251有关,在网上查看了一下发现string类并不是一个DLL的导出类,程序在执行的时候,可能会调用不动的DLL库,有些说的添加template  class __declspec( dllexport ) std::***没有用,警告依然在,程序直接运行,也还是会崩溃。

最后找到了一个说的比较深入,也比较有用的方法。

这是因为STL里的string类并非是一个DLL的输出类,这会导致类的成员变量name无法正确输出。
在你将CTest定义为一个导出类后,CTest中的所有成员函数都将编译连接为DLL的输出函数。包括一些隐含的构造/析构函数以及operator=等。如果一个类的一些PUBLIC成员变量不是输出类,那么DLL的使用者对这些公共成员的方法的访问可能会导致访问不同的VC运行库。

分析下面的代码:

CTest  test;  
// 调用CTest的构造函数,由于CTest是输出类,构造函数也是DLL的输出函数,构造函数调用的string的构造函数,string调用VC运行库分配内存,这个时候string类使用的运行库是与CTest实现所在的DLL进行连接的那个VC运行库

test.intValue  =  3;           //没有问题  
// 没有问题,因为对整数的赋值与运行库无关

test.name  =  "name";          //编译、连接都通过,运行时出现内存访问异常:  
                               //test.name中的数据指针是非法的堆指针
  
// 由于string不是DLL的输出类,所以string的operator=不是一个DLL内部的函数,
对string的operator=成员的访问会导致编译器调用当前的模块(EXE)使用的VC运行库中的函数,这便产生了问题。



// 同样在析构的时候也可能产生这样的问题

解决的办法是
在编译两个模块时选择相同类型的DLL版本的VC运行库,相同类型的静态的VC运行库不解决问题,因为在这种情况下,不同的模块分别包含VC静态运行库的静态数据和代码。

 

其实问题很简单,为了便于说明问题,假定CTest实现所在的DLL是TEST.DLL, CTest的使用者是CLIENT.EXE。
在构造CTest的时候,CTest的构造函数调用string的构造函数,这个时候string使用的是与TEST.DLL连接的运行库中的内存分配函数。
当CLIENT.EXE代码中对string赋值的时候,会导致string重新分配内存,这个时候string使用的是与CLIENT.EXE连接的运行库中的内存分配函数。在这个过程中,string会将在构造时分配的内存释放掉,这些内存是由与TEST.DLL连接的运行库的内存分配函数分配的,但是却由与CLIENT.EXE连接的运行库的内存分配函数释放,如果TEST.DLL和Client.EXE使用的是同样类型的运行库DLL(都使用Debug Multi-thread DLL, 或者Release Multi-Thread DLL), 那么是不会有问题的,因为这个时候VC的运行库中的malloc, free使用同一的CRT内部数据。

如果使用不同的CRT库,那么实际上在CLIENT.EXE运行的时候,进程的地址空间里实际上存在两份不同的CRT的代码和数据(分别被TEST.DLL和CLIENT.EXE使用), 当一个CRT的free函数企图释放由另一个CRT通过malloc分配的函数的时候,就会出现问题,这个时候CrtIsValidHeapPointer函数就会认为这不是一个有效的堆指针。

那么如果使用同样的静态库呢?这个问题同样存在,因为如果使用静态库,在CLIENT.EXE运行的时候,进程的地址空间里还是会存在两份CRT的代码和数据,尽管他们的代码和数据结构很多都一样。

类似的问题有通过一个CRT的fopen获得一个FILE指针,然后由另一个CRT的fclose关闭等等。




否则,在释放内存的时候,那么CrtIsValidHeapPointer就会告诉你这快内存不是由这个CRT分配的。

 

转载注明出处http://www.cnblogs.com/WJIUYANG/p/3509316.html

转载于:https://www.cnblogs.com/WJIUYANG/p/3509316.html

### C++ 中使用 libpng 处理 iCCP 已知不正确 sRGB 配置文件警告 当处理 PNG 图像时,可能会遇到 `iCCP: known incorrect sRGB profile` 的警告。这通常是因为图像中的 ICC 配置文件与标准的 sRGB 配置文件不符。 为了消除此警告,在读取 PNG 文件之前设置 libpng 库忽略特定类型的 chunk 是一种常见做法[^1]: ```cpp #include <png.h> #include <stdio.h> void read_png(const char* filename) { FILE *fp = fopen(filename, "rb"); png_structp png_ptr; png_infop info_ptr; /* 创建读取结构 */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); return; } /* 设置错误恢复机制 (可选)*/ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(fp); return; } /* 告诉 libpng 忽略 iCCP chunk */ png_set_option(png_ptr, PNG_IGNORE_aDAMATE, PNG_OPTION_ON); /* 初始化信息结构 */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return; } /* 设置输入控制 */ png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); /* 读取图片信息 */ png_read_info(png_ptr, info_ptr); /* 继续正常的解码过程... */ /* 清理资源 */ png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(fp); } ``` 上述代码展示了如何通过调用 `png_set_option()` 函数并传递适当参数来指示 libpng 忽略有问题的 iCCP 数据块。这样可以在不影响其他功能的情况下有效地抑制该警告消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值