How to correctly reset _bstr_t to `NULL`

In the snippet below (simplified loop script)

_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 

What I expect after another.Assign(NULL) :

  • SysFreeString() NOT called
  • another set to NULL
  • ref-count decreases to 1
  • original has ref count=1 with existing BSTR content.

What happened:

  • SysFreeString() is called for the base BSTR both another and original
  • another set to NULL
  • ref-count original remains 2

another.Assign(NULL) seems to free the base BSTR for original and another .
We had an unexpected failure, because during the encoding, I thought that _bstr_t::Assign() would decrease the reference count instead of freeing up the BSTR right away.

How to properly reset another to NULL not affect original ?

The following is a description of Assign from 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
source share
1 answer

The implementation of _bstr_t::Assign() been updated as indicated by Igor Tandetnik in his comment .

Here's the implementation in VS2010 and it works as expected:

 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); } } } 
0
source

Source: https://habr.com/ru/post/1492890/


All Articles