Re[5]: Взрывоопасная смесь new[]+memmove+delete[]
От: Al-Ko  
Дата: 19.07.02 12:02
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>Здравствуйте Al-Ko, Вы писали:


AK>>когда их копируют из m_pData в pNewData, они копируются в pNewData, а в m_pData остаются, или нет? Их уже два экземпляра, не так ли?Если остаются, то delete[] m_pData должно работать корректно.

AK>>Спасибо, я учту замечания и проверю с TYPE c деструкторами — с простыми типами это работает хоть с пятимерными массивами, только Redimension можно делать только последнему измерению (как в SafeArray или бейсиковских массивах)

Vi2>Введу псевдо-обозначения О(ptr) — объект О типа TYPE имеет указатель на динамически выделяемую память ptr (есть аналогия с классом AKVector), чтобы было видно влияние деструктора.


Vi2>
m_pData->>    O0(ptr0),O1(ptr1),...,ON(ptrN), где N=m_nSize

Vi2>    TYPE* pNewData =  new TYPE[nNewSize];
pNewData->>    O'0(NULL),O'1(NULL),...,O'N(NULL),O'N+1(NULL), где N=m_nSize

Vi2>    memmove(pNewData, m_pData, m_nSize * sizeof(TYPE));
pNewData->>    O0(ptr0),O1(ptr1),...,ON(ptrN),O'N+1(NULL), где N=m_nSize

Vi2>    delete [] m_pData;
Vi2>~O0 освободил ptr0,~O1 освободил ptr1,...,~ON освободил ptrN, где N=m_nSize
m_pData->>    O0(ptr0),O1(ptr1),...,ON(ptrN), где N=m_nSize

Vi2>    m_pData = pNewData;
m_pData->>    O0(ptr0),O1(ptr1),...,ON(ptrN),O'N+1(NULL), где N=m_nSize
Vi2>

Vi2>Если теперь попытаться освободить delete [] m_pData; — в деструкторе или методе Add — произойдёт следующее
Vi2>~O0 будет освобождать ptr0 и вылетит по ексепшену (прерыванию).

Vi2>Конечно, лучше бы представить это всё графически, но нет у меня такой возможности.


да, вот так оно веселее будет:

void AKVector<TYPE>::Remove(long nIndex, long nCount /* = 1 */)
    {
  
        ATLASSERT(nIndex >= 0);
        ATLASSERT(nCount >= 0);
    
        ATLASSERT(nIndex + nCount <= m_nSize);
    
        long nNewSize = m_nSize - nCount;

        TYPE* pNewData;

        if(nNewSize > 0)
            pNewData =  (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
        else
            pNewData = NULL;

        if(nIndex > 0)
            memcpy(pNewData, m_pData, nIndex * sizeof(TYPE));

        if(nIndex < nNewSize)
            memcpy(&pNewData[nIndex], &m_pData[nIndex + nCount], (nNewSize-nIndex)* sizeof(TYPE));
        
        DestructElements<TYPE>(&m_pData[nIndex], nCount);
        delete[] (BYTE*)m_pData;

        m_nSize = nNewSize;
        m_pData = pNewData;    
    }

inline void STDAPICALLTYPE DestructElements(TYPE* pElements, int nCount)
        {
    ATLASSERT(nCount == 0 ||
        AtlIsValidAddress(pElements, nCount * sizeof(TYPE)));

    // call the destructor(s)
    for (; nCount--; pElements++)
        pElements->~TYPE();
       }


(аналогичные изменения для Add и Insert)

проверял — работает, еще раз благодарю за замечание
Старый глюк лучше новых двух!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.