const char* CRecordset::Get(const char* szField)
{
    try
    {
        m_strRet = _bstr_t(m_pRecordset->GetCollect(szField));
        return m_strRet.c_str();
    }
    catch (_com_error e)
    {
        BSTR szErr;
        e.ErrorInfo()->GetDescription(&szErr);        CDebugOutPut::ErrOut(szErr);
        return NULL;
    }
}CRecordset是自己写的类,strRet是一个string的成员变量,pRecordset是_RecordsetPtr
打算把ADO根据自己的需要进行一次封装,但是问题出在 _bstr_t 的析构上!在这个函数生命周期结束时,_bstr_t类在析构时,出问题了!难道这里也存在内存泄漏之类的问题??

解决方案 »

  1.   

    我没做过ADO,但看了代码,觉得
    可能是
    m_pRecordset->GetCollect(szField)反回的东西出了问题。
    还有
    m_strRet = _bstr_t(m_pRecordset->GetCollect(szField));赋值如遇到中间的NULL字符时是不是不正确了。
    _bstr_t应该不会存在泄恨漏问题。
      

  2.   

    在这个函数生命周期结束时,m_strRet真的会发生析构?
      

  3.   

    m_pRecordset->GetCollect(szField)返回的类型是WCHAR的吗?在中间用个临时变量观察一下试试吧,我测试了类似的函数使用_bstr_t没问题啊
      

  4.   

    如果是_bstr_t析构出问题,那应该是由于两个字符类对象同时用到一个字符资源,在前一个析构时释放了该内存,但是第二个对象析构时又去释放一次,因此出错。建议去看看_bstr_t类的构造函数说明。
      

  5.   

    m_strRet = _bstr_t(m_pRecordset->GetCollect(szField));
    这里肯定有问题,我不知道m_pRecordset->GetCollect(szField)返回值是什么,如果返回值是BSTR,那么肯定会内存泄露,请看_bstr_t的原型:
    _bstr_t( ) throw( );
    _bstr_t(
       const _bstr_t& s1 
    ) throw( );
    _bstr_t(
       const char* s2 
    );
    _bstr_t(
       const wchar_t* s3 
    );
    _bstr_t(
       const _variant_t& var 
    );
    _bstr_t(
       BSTR bstr,
       bool fCopy 
    );我们知道BSTR在不修改其字符串长度的前提下,可以像一个LPWSTR一样使用。事实上我们可以找到BSTR的定义:
    typedef LPWSTR BSTR;然而,BSTR和WSTR是不一样的,BSTR的指针所指的地址以前的4个字节的地方放着BSTR的长度,这样系统在释放内存的时候才知道要释放多少字节。BSTR实际上是一个COM中用来拷贝数据的内存缓冲区结构,并不要求一定以\0结束,只是用来做字符串使用的时候以\0结束。BSTR用SysAllocString和SysFreeString来分配和释放。那问题就来了,加入这里GetCollect返回的是BSTR,根据COM的约定,应该由你自己用SysFreeString来释放。然而你干了什么,你做了一个临时变量_bstr_t()用括号把它包了一下,这里会用_bstr_t(const wchar_t* s3);这个构建函数来创建这个临时变量,而这个函数的作用很简单,就是创建一个BSTR,所以你所做的,就是又复制了一个BSTR,并且在函数退出的时候,析构函数释放掉它而已。然而GetCollect返回的那个BSTR你并没有释放,这里肯定会内存泄露
      

  6.   

    GetCollect这是个什么玩艺儿,返回值是什么
      

  7.   

    GetCollect是ADO里获取字段记录值的方法。返回一个 _variant_t本来是不需要用个_bstr_t括起来的,在VC7里可以直接赋值,但为了兼容VC6而加上去的如果不这么做,那应该怎么做呢?
      

  8.   

    最保险的办法是将这个_variant_t类型判断一下是否bstr,是的话将成员bstrVal取出来,再用WideCharToMultiByte转成char数组,这样没有那些自动构造析构的魔术,安全得多。
      

  9.   

    _variant_t tmp;
            tmp = m_pRecordset->GetCollect(szField);
            _bstr_t tmp2 = tmp;
            m_strRet = _com_util::ConvertBSTRToString(tmp2);
            return m_strRet.c_str();
    这也泄露了啊??郁闷了..要怎么解决才好呢