老问题原先没搞明白:DLL工程使用了STL,出现告警。

teleinfor 2010-10-26 10:12:19
一个DLL工程,导出一个类,类的成员变量使用了stl map容器。不过是 Private属性,并没有导出这个容器,只是STL内部使用而已。结果告警4251.

class DLL
{
....
private:
map<int,int> m_map; // 这个map为了仅限于DLL内部使用而已,结果还是告警。
}

咋回事?
...全文
197 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
牛魔皇 2013-07-20
  • 打赏
  • 举报
回复
我也一直这样封装STL来用,心里没底,看了上面的说法,貌似暂时不会有啥问题
teleinfor 2010-10-28
  • 打赏
  • 举报
回复
谢谢了。
[Quote=引用 8 楼 abigwood 的回复:]
类的封装就是这样尴尬……不能在.h文件里出现map的对象。可以声明一个void*,在构造函数里给它new一个map,析构函数里释放掉,再定义一个宏来引用它。

.h:
class …
{
……
private
void * m_pMap__;
};
.cpp:
# define m_Map (*(map<…>*)m_pMap)
[/Quote]
teleinfor 2010-10-28
  • 打赏
  • 举报
回复
多谢!明白了,看起来DLL和导出类还是有点别扭的组合。不过我目前应该不会遇到这些个问题,stl封装进DLL,通过接口访问stl容器。可以认为采用了ADAPTOR模式设计。

[Quote=引用 13 楼 w_anthony 的回复:]
引用 12 楼 teleinfor 的回复:
非常感谢w_anthony的解答,清楚了不少。不过我还是很疑惑DLL导出类的应用,看起来我这里如果在DLL内部使用了map等stl容器,那么就还是有可能引入潜在的问题的。有一点不是十分明白,就是我使用map也仅仅限于DLL内部的实现算法而已,并没有提供外部直接操作stl对象的机会,比如我通过提供外部接口遍历或者查找stl的容器,但是就STL容器而言,……
[/Quote]
翅膀又硬了 2010-10-28
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 abigwood 的回复:]
class的DLL是二进制不兼容的,要想跨编译器使用,就得自己保证导出的class是二进制兼容的
[/Quote]
STL是模板拷贝,而不是源码拷贝。最好动态库别用STL
w_anthony 2010-10-28
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 teleinfor 的回复:]
非常感谢w_anthony的解答,清楚了不少。不过我还是很疑惑DLL导出类的应用,看起来我这里如果在DLL内部使用了map等stl容器,那么就还是有可能引入潜在的问题的。有一点不是十分明白,就是我使用map也仅仅限于DLL内部的实现算法而已,并没有提供外部直接操作stl对象的机会,比如我通过提供外部接口遍历或者查找stl的容器,但是就STL容器而言,仅仅局限于dll内部,这样以你的说法好像还是做不……
[/Quote]

既然使用了DLL导出类,就不要想跨编译器链接了,因为各编译器的C++修饰名称不同,几乎是不可能通用的。同一个编译器但是版本不同的话,不保证一定能用。能用的前提是两个版本的sizeof(map)要相等,否则还是不能用,因为一旦sizeof(map)不相等,那么sizeof(导出类)也将不相等,这样会不会出问题以及可能会出什么问题,就要看具体情况了。
我个人认为导出类本身就是一个不“干净”的东西,没必要考虑它的通用性。要想跨编译器使用的话,不含虚析构的纯虚类作为接口是比较常用的方法,比如那些COM接口都是这种。
LZ这里不跨编译器使用,不在外部直接访问map成员,没有安全问题,可以忽略这个warning。


teleinfor 2010-10-28
  • 打赏
  • 举报
回复
非常感谢w_anthony的解答,清楚了不少。不过我还是很疑惑DLL导出类的应用,看起来我这里如果在DLL内部使用了map等stl容器,那么就还是有可能引入潜在的问题的。有一点不是十分明白,就是我使用map也仅仅限于DLL内部的实现算法而已,并没有提供外部直接操作stl对象的机会,比如我通过提供外部接口遍历或者查找stl的容器,但是就STL容器而言,仅仅局限于dll内部,这样以你的说法好像还是做不到理论上的安全,比如编译环境的依赖性。我不解的地方在于一旦我的DLL生成那么内部的数据结构和访问机制是不是已经确定了呢,和所在工程的编译选项会有相关性么?

不过看起来就我目前的场景而言,这种使用应该是问题不大的,不过我还是有点担心,这种对于stl的使用,应该如何结合DLL导出类进行设计呢?仅仅是通过void*指针回避warning看起来并不解决实质性问题。
[Quote=引用 7 楼 w_anthony 的回复:]
首先你要搞清楚为什么会有warning?编译器到底怕你犯什么错误,以及你究竟有没有犯这个错误?
C4251的意思通俗地讲就是某一个导出类它存在一个没有导出的类型是非内置类型(比如类)的成员变量。比如

C/C++ code

class A {
public:
void func();
};
class DLLEXPORT B {
public:
A m_a;……
[/Quote]
Sou2012 2010-10-27
  • 打赏
  • 举报
回复
警告一般是可以忽略的。。。
w_anthony 2010-10-27
  • 打赏
  • 举报
回复
补充一下我自己7L说的那个class A必须要有一个构造函数,才会有waring。
aBigWood 2010-10-27
  • 打赏
  • 举报
回复
class的DLL是二进制不兼容的,要想跨编译器使用,就得自己保证导出的class是二进制兼容的
w_anthony 2010-10-27
  • 打赏
  • 举报
回复
另外假设LZ这里的map是public的,因为map是一个模板,它的代码都在头文件里面,所以即使在Exe里面调用map的任何一个成员函数也都是可以通过链接的。但是除非DLL和EXE使用同一个版本的编译器,并且代码生成一栏都选择了MD或者MDd,否则调用非只读的map成员函数,最终都可能导致程序挂掉(调用时刻挂或者析构时刻挂,看具体情况)或者内存泄漏。挂掉或者内存泄漏的原因就是内存分配的模块不同,释放非本模块分配的内存将会抛异常,VS2003以前不会主动捕获这个错误,因此程序挂掉,而VS2005以后会捕获异常,但是内存实际上没能释放,所以就泄漏了。虽然可以用map的第四个参数指定自定义的内存分配器解决这个问题,不过这个就不是三言两语讲得清了,而且也偏离LZ的主题了。
aBigWood 2010-10-27
  • 打赏
  • 举报
回复
类的封装就是这样尴尬……不能在.h文件里出现map的对象。可以声明一个void*,在构造函数里给它new一个map,析构函数里释放掉,再定义一个宏来引用它。

.h:
class …
{
……
private
void * m_pMap__;
};
.cpp:
# define m_Map (*(map<…>*)m_pMap)
w_anthony 2010-10-27
  • 打赏
  • 举报
回复
首先你要搞清楚为什么会有warning?编译器到底怕你犯什么错误,以及你究竟有没有犯这个错误?
C4251的意思通俗地讲就是某一个导出类它存在一个没有导出的类型是非内置类型(比如类)的成员变量。比如

class A {
public:
void func();
};
class DLLEXPORT B {
public:
A m_a;
}

这样就会有这个warning,当你在Exe项目里面链接这个dll,定义了B b,但是b.m_a.func()是通不过链接的,因为A没有导出来。即使这里的A m_a是private的,编译器可不管你这个,还是会有这个warning。
而LZ这里并没有这种用法,直接用#pragma warning(disable : 4251)屏蔽掉就行了。
ouyh12345 2010-10-27
  • 打赏
  • 举报
回复
如果是导出类的话,这警告不能忽视
teleinfor 2010-10-27
  • 打赏
  • 举报
回复
james,啥意思啊?是不鼓励我这么使用还是咋的?没整明白啊。。。我这个DLL内部由于需要进行快速的查找,所以我想使用STL的map/set/hash_map容器实现部分功能。见到些个warning,总是觉得有不爽的感觉。上面的两位xd说warning基本上可以不理,不敢随意啊,还是严谨点好。
[Quote=引用 2 楼 jameshooo 的回复:]
再抽象一层类用于导出,导出类中不要出现任何模板类(包括STL)名称,无论是不是私有。同一个模板类名称,相同的模板参数,在不同的模块看来完全是不同的类型,甚至内存布局都可能不同。
[/Quote]
oyljerry 2010-10-26
  • 打赏
  • 举报
回复
有些可以忽略
用vs2005等新编译器
jameshooo 2010-10-26
  • 打赏
  • 举报
回复
再抽象一层类用于导出,导出类中不要出现任何模板类(包括STL)名称,无论是不是私有。同一个模板类名称,相同的模板参数,在不同的模块看来完全是不同的类型,甚至内存布局都可能不同。
fishion 2010-10-26
  • 打赏
  • 举报
回复
警告?警告而已。。

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧