4

在下面的片段中(循环的简化场景)

_bstr_t original(OLESTR("MyString")); // ref-count = 1
_bstr_t another;
another = original; // ref-count = 2
// do something with another
another.Assign(NULL); // expected: ref-count = 1, and another = NULL
// reset another to NULL before doing other operations

我期望another.Assign(NULL)的是:

  • SysFreeString()不被称为
  • another设定为NULL
  • ref-count 减为 1
  • originalref count=1现有BSTR内容。

发生了什么:

  • SysFreeString()被称为底层证券BSTRanotheroriginal
  • another设定为NULL
  • original残骸的参考计数2

another.Assign(NULL)似乎解除了 和 的底层证券BSTRoriginal分配another
我们发生了意外的崩溃,因为在编码过程中我认为_bstr_t::Assign()会减少引用计数而不是立即取消分配BSTR.

如何anotherNULL不影响的情况下正确重置original

请在下面找到Assignfrom的实现VC++ 6

// assignment operator copies internal data and increases reference count
inline _bstr_t& _bstr_t::operator=(const _bstr_t& s) throw()
{
    const_cast<_bstr_t*>(&s)->_AddRef();
    _Free();
    m_Data = s.m_Data;

    return *this;
}
// but _bstr_t::Assign() calls _bstr_t::Data_t::Assign() 
// without touching ref count
inline void _bstr_t::Assign(BSTR s) throw(_com_error)
{
    if (m_Data != NULL) {
        m_Data->Assign(s); 
    } 
    else {
        m_Data = new Data_t(s, TRUE);
        if (m_Data == NULL) {
            _com_issue_error(E_OUTOFMEMORY);
        }
    }
}
// it calls _bstr_t::Data_t::_Free() instead of _bstr_t::_Free() !
inline void _bstr_t::Data_t::Assign(BSTR s) throw(_com_error)
{
    _Free();
    if (s != NULL) {
        m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char*>(s), 
                                            ::SysStringByteLen(s));
    }
}
// this _Free() straight away deallocates the BSTR!
inline void _bstr_t::Data_t::_Free() throw()
{
    if (m_wstr != NULL) {
        ::SysFreeString(m_wstr);
    }

    if (m_str != NULL) {
        delete [] m_str;
    }
}
// properly decrements ref count
inline void _bstr_t::_Free() throw()
{
    if (m_Data != NULL) {
        m_Data->Release();
        m_Data = NULL;
    }
}
4

1 回答 1

0

正如Igor Tandetnik在他的评论中提到的那样,实施_bstr_t::Assign()已经更新。

这是 VS2010 中的实现,它按预期工作:

inline void _bstr_t::Assign(BSTR s) 
{
    _COM_ASSERT(s == NULL || m_Data == NULL || m_Data->GetWString() != s);

    if (s == NULL || m_Data == NULL || m_Data->GetWString() != s)
    {
        _Free();

        m_Data = new Data_t(s, TRUE);
        if (m_Data == NULL) {
            _com_issue_error(E_OUTOFMEMORY);
        }
    }
}
于 2013-07-25T05:58:20.077 回答