【问题标题】:How to clean up _variant_t如何清理 _variant_t
【发布时间】:2017-01-02 11:39:48
【问题描述】:

我的泄漏检查器告诉我这个函数有第二次机会异常。

BOOL CADORecordset::SetFieldValue(LPCTSTR lpFieldName, CString strValue)
{
    _variant_t vtFld;

    if(!strValue.IsEmpty())
        vtFld.vt = VT_BSTR;
    else
        vtFld.vt = VT_NULL;

    vtFld.bstrVal = strValue.AllocSysString();

    BOOL bret = PutFieldValue(lpFieldName, vtFld);
    SysFreeString(vtFld.bstrVal);

    return bret;
}

现在_variant_t 有一个类型 BSTR 成员 (bstrVal)。我们know 需要使用 SystemFreeString() 取消分配 BSTR,这是在上面的代码中完成的,但是由于这个 BSTR 是 _variant_t 的成员,他有自己的析构函数可以清理,谁应该真正清理bstrVal 成员在这种情况下?

inline _variant_t::~_variant_t() throw()
{
    ::VariantClear(this);
}

在我看来,这似乎试图再次清理已被SysFreeString() 清理的内存导致异常? documentation 说它清除了变体,但不清楚它到底清除了什么,它是否也释放了 bstrVal

如果我删除调用 SysFreeString(vtFld.bstrVal); 这确实删除了第二次机会异常,但我真的很想知道这是正确的做法,因为文档没有提供足够的信心。

【问题讨论】:

  • 你的帮助太大了,像_variant_t 这样的包装类从来都不是一个好主意。 BSTR 被删除两次,一次被您删除,一次被 variant_t 删除。您也不应该访问其字段。您只需要_variant_t vtFld(strValue);vtFld = strValue;,其余的都是自动的。
  • @HansPassant:由于VT_NULL 需要在strValue 为空时传递给PutFieldValue(),因此使用类似这样的东西会更正确:_variant_t vtFld; if(!strValue.IsEmpty()) vtFld = strValue; else vtFld.vt = VT_NULL; return PutFieldValue(lpFieldName, vtFld);

标签: c++ com variant


【解决方案1】:

_variant_t 超出范围时会自动清理其数据。您正在手动调用SysFreeString(),但之后您没有将bstrVal 设置为NULL 或将vt 设置为VT_EMPTY。因此,当variant_t 析构函数调用VariantClear() 清理数据时,它会再次尝试释放bstrVal 并崩溃。

所以,根本不要手动调用SysFreeString()。如果您需要手动重置 variant_t,请改用其 Clear() 方法:

vtFld.Clear();

【讨论】:

    【解决方案2】:

    variant_t 拥有其数据并使用VariantClear() 函数进行清理:

    该函数通过将 vt 字段设置为 VT_EMPTY 来清除 VARIANTARG。 VARIANTARG 的当前内容首先发布。 如果 vtfield 是 VT_BSTR,则释放字符串。如果 vtfield 是 VT_DISPATCH,则释放对象。如果 vt 字段设置了 VT_ARRAY 位,则释放数组。

    _variant_t 是一个负责内存管理的包装器。类似于_bstr_t,它管理一个BSTR;他们一起工作得最好。与其手动设置vt 字段和bstrVal 值,不如使用variant_t 构造函数或operator=_bstr_t 将分配BSTR 所有权并将其传递给_variant_t。我不记得使用它的细节。只需在 MSDN 上查找详细信息。

    【讨论】:

    • 我并没有真正使用过变体,也不太熟悉它的结构或VARIANTARG,但它看起来像它所说的那样,它会释放 BSTR 权利,而我没有必须打电话给SysFreeString(vtFld.bstrVal);
    • 不,你不需要打电话给SysFreeString()variant_t 拥有BSTR 并且会为你释放它
    • 如果你有裸C,你必须手动管理资源。对于 C++ 特殊类 _variant_t_bstr_t 和另一个用于数组的类已经为您提供。
    猜你喜欢
    • 2012-05-11
    • 1970-01-01
    • 2011-01-18
    • 2020-04-16
    • 2011-04-21
    • 2015-12-31
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多