VARIANT/Variant/TVariant
昨天发现系统中数据压缩解压部分有内存泄漏,上午研究了一番,发现还是实现的人对这几个东东不熟悉,现将研究结果罗列一番。
源代码如下:
1
long __fastcall UnVarCompress(VARIANT varRet,VARIANT *vaDest)
2
{
3
try
4
{
5
Variant vaSource;
6
Variant vaDestTmp;
7
vaDestTmp = vaDest;
8
vaSource = varRet;
9![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
ICompressionDisp xComp;
11
HRESULT hr = xComp.BindDefault();
12![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
if (FAILED(hr))
14
{
15
throw Exception("");
16
}
17![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
CompressionError xResult = xComp.Uncompress(vaSource, vaDestTmp, true);
19![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
if( xResult != xSuccess )
21![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
{
23
AnsiString strErr = xComp->GetErrorDescription(xResult);
24
xComp.Unbind();
25
throw Exception(strErr);
26
}
27![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
xComp.Unbind();
29![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
vaDest = vaDestTmp;
31
}
32
catch(...)
33
{
34
return -1;
35
}
36
return 1;
37
}
38![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
39
long __fastcall VARToDataSet(VARIANT varRet, AnsiString strFileName)
40
{
41
long l, h;
42
void *ppvdata;
43
TFileStream *fm = NULL;
44
VARIANT varTempRet;
45![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
46
try
47
{
48
UnVarCompress(varRet,&varTempRet);
49
varRet = varTempRet;
50
::SafeArrayGetLBound(varRet.parray, 1, &l);
51
::SafeArrayGetUBound(varRet.parray, 1, &h);
52
::SafeArrayAccessData(varRet.parray, &ppvdata);
53![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
//采用guid做文件名,在读取后应立即删除
55
fm = new TFileStream(strFileName, fmCreate);
56
fm->Write(ppvdata, h - l + 1);
57
::SafeArrayUnaccessData(varRet.parray);
58
}
59
__finally
60
{
61
delete fm;
62
fm = NULL;
63
}
64![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
65
return 0;
66
}
67![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
68![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
69
接口声明为:
70
template <class T> ziplib_tlb::CompressionError __fastcall CompressionDispT<T>::Uncompress(TVariant* vaSource, TVariant* vaUncompressed, TOLEBOOL bEndOfData);
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
32
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
38
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
39
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
40
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
41
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
42
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
46
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
48
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
59
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
60
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
61
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
62
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
63
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
64
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
65
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
66
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
67
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
68
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
69
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
70
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
VARToDateSet是最外层,直接被其他程序员调用
而VARToDateSet内部调用UnVarCompress,UnVarCompress又调用ICompression接口进行实际解压工作
先看UnVarCompress方法
第一感觉,有2个问题
首先觉得vaDestTmp = vaDest这句多余
另外,vaDest = vaDestTmp这句将解压后的数据返回出去也有问题
因为vaDestTmp是Variant类型,在UnVarCompress执行后将被释放,那么vaDest指向的将是无效的指针
但是实际应用时这个方法一直都工作正常阿!百思不得其解,于是跟踪了一番,终于发现问题所在
在vaDestTmp = vaDest后,vaDestTmp实际类型变成了VT_VARIANT | VT_REF,vaDestTmp.VArray指向的是vaDest,也就是说这时候vaDestTmp指向的实际数据是另一个VARIANT vaDest
xComp.Uncompress之后vaDest.parray被正确修改,得到了实际的解压数据
反而vaDest = vaDestTmp这句是多余的......
再来看VARToDataSet方法
实际上内存泄漏是出现在这个地方的,而且有2处
第一处是varRet,这个方法中没有调用::VaraintClear清除其中的内容
有人会说了,varRet是个VARIANT结构,结构当参数传入时实际只是传了个地址而已,并不是复制了一份传进来的,因此不应该在这里释放
的确时这样,不过在我们的已有的应用中,程序员都没有做释放的工作,所以只好在这里做了
第二处是解压后的varTempRet,也没有释放
知道了问题就好办了,修改的工作其实很简单
修改后的代码如下
1
long __fastcall UnVarCompress(VARIANT varRet1,VARIANT *vaDest)
2
{
3
try
4
{
5
Variant vaSource;
6
Variant vaDestTmp;
7
vaDestTmp = vaDest;
8
vaSource = varRet;
9![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
IXceedCompressionDisp xComp;
11
HRESULT hr = xComp.BindDefault();
12![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
if (FAILED(hr))
14
{
15
throw Exception("");
16
}
17![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
CompressionError xResult = xComp.Uncompress(vaSource, vaDestTmp, true);
19![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
if( xResult != xSuccess )
21![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
{
23
AnsiString strErr = xComp->GetErrorDescription(xResult);
24
xComp.Unbind();
25
throw Exception(strErr);
26
}
27![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
xComp.Unbind();
29
}
30
catch(...)
31
{
32
return -1;
33
}
34
return 1;
35
}
36![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
37
long __fastcall VARToDataSet(VARIANT varRet, AnsiString strFileName)
38
{
39
long l, h;
40
void *ppvdata;
41
TFileStream *fm = NULL;
42
VARIANT varTempRet;
43![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
try
45
{
46
UnVarCompress(varRet,&varTempRet);
47![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
::SafeArrayGetLBound(varTempRet.parray, 1, &l);
49
::SafeArrayGetUBound(varTempRet.parray, 1, &h);
50
::SafeArrayAccessData(varTempRet.parray, &ppvdata);
51
//采用guid做文件名,在读取后应立即删除
52
fm = new TFileStream(strFileName, fmCreate);
53
fm->Write(ppvdata, h - l + 1);
54
::SafeArrayUnaccessData(varTempRet.parray);
55
}
56
__finally
57
{
58
::VariantClear(&varRet);
59
::VariantClear(&varTempRet);
60
delete fm;
61
fm = NULL;
62
}
63![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
return 0;
65
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
32
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
38
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
39
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
40
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
41
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
42
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
46
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
56
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
58
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
60
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
62
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
63
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
65
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
再来说说类型转换的问题
C++Builder支持 VARIANT/Variant/TVariant
VARIANT是Windows定义的类型
Variant是BCB自己实现的类型,目的是为了兼容Delphi的Variant
TVariant则是对VARIANT的封装
用代码说话
Variant v;
VARIANT wv, *pwv;
TVariant tv, *ptv;
wv = v; pwv = v;
tv = v; ptv = v;
看看地址
&v: :0012F364
v.VArray: :00156DD8
&tv: :0012F354
tv.parray: :00156B10
ptv: :0012F364
ptv->parray: :00156DD8
&wv: :0012F2F0
wv.parray: :00156E18
pwv: :0012F364
pwv->parray: :00156DD8
看出什么问题?对,&v,ptv,pwv指向的都是v!而tv,wv则是对v的拷贝
比较有意思的是
VARIANT wv...
Varaint v1 = &wv;
Variant v2; v2 = &wv;
此时 v1.VArray指向的是 &wv,也就是说类型为 VT_VARIANT | VT_REF,而v2中VArray指向的是一份wv的内容的拷贝,类型与wv类型一致
产生这样的结果原因跟编译器有关
Varaint v1 = &wv实际跟Variant v1(&wv)是一样的,也就是说调用的是Variant的构造
Variant v2; v2 = &wv;实际是先构造v2,然后将&wv赋值给v2,调用的是v2重载的操作符=