카테고리 없음 2013. 4. 3. 11:27


Container 사용시 이터레이팅을 하면서 어떤 처리를 하다가 처리 로직에서 의도하지 않은

element 삭제가 발생할 수 있다.

예를들어 룸리스트를 가지고 있는 채널에서 for문을 돌며 해당 룸의 어떤 함수를 콜한다고

했을때 그 함수 로직에서 다른 함수의 콜에 콜을 타고 채널의 룸리스트 컨테이너의

element를 의도치 않게 삭제할 수 있다.

경우에 따라 정상 작동할 수 있고 예기치 않은 심각한 오류가 발생할 수 있는데...

오류 발생시 정말 뜬금없는 곳에서 크래시 될 수가 있다.


그래서 foreach와 같은 형식으로 메크로를 만들어서 이 메크로를 썼을 경우 의도하지 않은

삭제가 발생하면 크래시 되게끔 코드를 만들어 보았다.


2가지 케이스가 있는데.

// 이 메크로를 사용하면 FOR_EACH시 해당 리스트의 요소를 삭제하지 않을거라는 의미
#define FOR_EACH( _Class, _pointer, _Container ) for( TempPointer<_Class> _pointer( _Container.GetHead(), _Container.GetDeleteFlag() ); \
!(_Container).IsEnd(); _pointer = (_Container).GetNext() )


///////////// 포인터를 래핑한 템플릿 클래스 /////////////
template< class _T >
class TempPointer
{
public:
TempPointer( _T * pPointer, bool & bDelete );
virtual ~TempPointer();

_T * operator *();
const _T * operator *() const;

_T * operator ->();
const _T * operator ->() const;

TempPointer<_T> & operator =( _T * pRHSItem );
bool operator !=( _T * pRHSItem );

private:
_T * m_pPointer;
bool & m_bDelete; // 레퍼런스 클래스 변수
};

// & m_bDelete 초기화
template< class _T >
inline
TempPointer<_T>::TempPointer( _T * pPointer, bool & bDelete ) : m_pPointer(pPointer), m_bDelete(bDelete)
{
}

template< class _T >
inline
TempPointer<Type>::~TempPointer()
{
    // 소멸자 호출시 참조로 받은 해당 원본 값을 바뀌준다( 컨테이너의 m_bDelete )
    m_bDelete = true;
};

 

#include <map>
#include <algorithm>

/////////////////// std::Map 래핑 클래수 ///////////////////

template< class _Key, class _T, class _Compare = std::less< _Key > >
class CMap
{
public:
typedef std::map< _Key, _T, _Compare > Container;

public:
Container m_Container;
bool m_bDelete; // <-- 요 클래스 변수에 의해 체크 되어짐

public:
CMap()
{
    m_bDelete = true;
};

inline bool & GetDeleteFlag()
{
    m_bDelete = false;
    return m_bDelete;
}

inline bool Delete( _Key key )
{
    // 해당 컨테이너에서 의도하지 않은 삭제인경우..
    if( m_bDelete == false )
    {
        ASSERT(FALSE);
    }

// 블라 블라
}

// 리턴값은 _T
inline _T GetHead();
inline _T GetNext();
inline bool Insert();
inline bool IsEnd();
};


int main()
{

CMap<int, Channel*> mapList;

mapList.Insert( 1, new Channel() );
mapList.Insert( 2, new Channel() );
mapList.Insert( 3, new Channel() );

FOR_EACH( Channel, pChannel, mapList )
{
    // 블라 블라

// 의도하지 않은 컨테이너의 element 삭제시 ASSERT
mapList.Delete( 2 );

}

// 스코프를 벗어나면 정상 처리
mapList.Delete( 2 );

}


다른 방법은 Lamda 사용

template<class _Container , class Lambda>
static inline void
LAMBDA_FOR_EACH( Container * pContainer, Lambda Function )
{
    _Container->SetDeleteFlag( FALSE ); // 컨테이너의 m_bDelete = false;

auto * pItr = pContainer->GetHead();
while( !(_Container).IsEnd() )
{
    Function( pItr ); // <-- 요 로직에서 Delete발생한 경우 크래시
    pItr = pContainer->GetNext();
}

_ Container->SetDeleteFlag( TRUE ); // 컨테이너의 m_bDelete 변수 초기화(true)

}

 

int main()
{
      CMap<int, Channel*> mapList;

mapList.Insert( 1, new Channel() );
mapList.Insert( 2, new Channel() );
mapList.Insert( 3, new Channel() );

LAMBDA_FOR_EACH( mapList, [](Channel * pIter) {

// 블라 블라

// 의도하지 않은 컨테이너의 element 삭제시 ASSERT
mapList.Delete( 2 );

} );

// 스코프를 벗어나면 정상 처리
mapList.Delete( 2 );

}

의도하지 않은 컨테이너 element Delete를 체크하기 위한 코드인데..문제 없이 정상 작동

할려나..


posted by 알 수 없는 사용자
: