달력

082018  이전 다음

  •  
  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
글쎄 한동안 잘 사용해오던 

STL의  remove_if와 unique 함수의 버그(?)같은 것을 찾았다.

둘다 특정 조건에 부합되는 부분을 일정 위치 이후로 옮기고, 그 위치를 리턴 하는 방식으로 데이터를 정리할 때 사용한다.

// 일반적으로 아래와 같이 사용을 한다.
std::vector<int> vecAny;

std::vector<int>::iterator it = std::remove_if( vecAny.begin(), vecAny.end(), ANYFunction );
if( it !=  vecAny.end() )
{
     vecAny.erase( it,  vecAny.end() );
}

그런데 이 놈의 것이 헛질거리를 하는 것을 본 것이 
std::vector<ANY_InstancePointerPOINTER> vecAny;
  std::vector<int>::iterator it = std::remove_if( vecAny.begin(), vecAny.end(), ANYFunction );
if( it !=  vecAny.end() )
{
    std::for_each( it,   vecAny.end(), _ANY_INSTANCE_REMOVE );
    vecAny.erase( it,  vecAny.end() );
}

위와 같이 잘 쓰고 있었다. 그런데.

이넘이 엄한 짓을 하고 있었다.

remove_if 시 정렬이 it가 가리키고 있는 곳과 잘 정리해서 준줄 알았는데, 주소값을 보면 중복적으로 처리되어 있는 부분이 있다.

즉. std::for_each를 이용해서 삭제를 할 경우 실제 instance가 앞쪽에 정렬되어 있는 넘과 같아서 남아 있어야 할 넘이 지워지는 경우까지 발생했다.

이와 같은 문제는 std::unique에서도 동일하게 발견되었다.

이 넘들 땜시 갑자기 죽어나가는 상황을 찾느라... ㅠ.ㅠ

결국 앞의 remove_if는 방법을 바꿔서 처리했다.

// 기존 방식
std::vector<int>::iterator it = std::remove_if( vecAny.begin(), vecAny.end(), ANYFunction );
if( it !=  vecAny.end() )
{
     vecAny.erase( it,  vecAny.end() );
}

// 문제 회피 방식
std::vector<int>::iterator it = std::find_if( vecAny.begin(), vecAny.end(), ANYFunction ); 
while(  it  !=  vecAny.end() )
{
   delete *it;
   vecAny.erase(it);
   if( vecAny.empty() == true ) break;

    it = std::find_if( vecAny.begin(), vecAny.end(), ANYFunction ); 
}

// unique의 경우는 보다 길어 졌다.
Dummy로 한쪽으로 옮겨놓고 원래 Container로 unique하게 만들때, 일일이 검사하는 방법으로 처리했다..
길어서 내용은 봐서~~ 나중에.. 

여하튼 참 고민스럽게 만든 부분들 이었다..

 
Posted by 촌돌애비
TAG stl, vc++

댓글을 달아 주세요

std::remove_if ....

삽질 2011.11.06 15:00
remove_if 가 지울 값을 뒤로 보내고 지울값 처음 위치를 반환한다. 
즉 erase를 함께 사용해야 한다.
특히 list의 remove, removeif맴버는 algorithm의 remove, remove_if와 좀 다른 동작을 합니다. 
list구조상 std::erase( std::remove(...) ) 계열쓰면 효율이 떨어 지게 때문에 그런 동작을 하는것을로 알고 있습니다. 

Ex.)
// edit 대상 instance 지우기
auto fnLambdaDel = [&]( LP_RCV_SCANSET_DYN pInfoScanset )->bool{ 
if( infoRange.timeBgn > pInfoScanset->timeScanData ||
infoRange.timeEnd < pInfoScanset->timeScanData) return false;
delete pInfoScanset;
return true;
};

// scanset 버퍼에서 지우기.. remove_if는 조건에 맞는 것을 뒤로 보낸다. 그리고 그 시작위치를 리턴한다.
auto itDelBgn = std::remove_if( m_vecScanset.begin(), m_vecScanset.end(), fnLambdaDel );
m_vecScanset.erase(itDelBgn, m_vecScanset.end());


template < class ForwardIterator, class Predicate >
  ForwardIterator remove_if ( ForwardIterator first, ForwardIterator last,
                              Predicate pred );

Remove elements from range

Applies pred to the elements in the range [first,last), and removes those for which it does not return false from the resulting range. The resulting range consists of the elements between first and the iterator returned by the function, which points to the new end of the range.

The relative order of the elements not removed is preserved, while the elements past the new end of range are still valid, although with unspecified values.

The behavior of this function template is equivalent to:
1
2
3
4
5
6
7
8
9
template < class ForwardIterator, class Predicate >
  ForwardIterator remove_if ( ForwardIterator first, ForwardIterator last,
                              Predicate pred )
{
  ForwardIterator result = first;
  for ( ; first != last; ++first)
    if (!pred(*first)) *result++ = *first;
  return result;
}


Notice that in this example implementation the elements past the new end are not altered, but alternative implementations may change their values.

Parameters

first, last
Forward iterators to the initial and final positions in a sequence. The range used is [first,last), which contains all the elements between first and last, including the element pointed by first but not the element pointed by last.
pred
Unary predicate taking an element in the range as argument, and returning a value indicating the falsehood (with false, or a zero value) or truth (true, or non-zero) of some condition applied to it. This can either be a pointer to a function or an object whose class overloads operator().

Return value

A forward iterator pointing to the new end of the sequence, which now includes all the elements for which pred was false.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// remove_if example
#include <iostream>
#include <algorithm>
using namespace std;

bool IsOdd (int i) { return ((i%2)==1); }

int main () {
  int myints[] = {1,2,3,4,5,6,7,8,9};            // 1 2 3 4 5 6 7 8 9

  // bounds of range:
  int* pbegin = myints;                          // ^
  int* pend = myints+sizeof(myints)/sizeof(int); // ^                 ^

  pend = remove_if (pbegin, pend, IsOdd);        // 2 4 6 8 ? ? ? ? ?
                                                 // ^       ^
  cout << "range contains:";
  for (int* p=pbegin; p!=pend; ++p)
    cout << " " << *p;

  cout << endl;
 
  return 0;
}


Output:
range contains: 2 4 6 8

Complexity

Applies pred as many times as the number of elements in the range [first,last), and performs as many assignment operations as the number of elements not removed.

'삽질' 카테고리의 다른 글

[펌]테이블/ 테이블스페이스별 사용량 확인  (0) 2012.02.03
ImageSafer... Image Protection  (1) 2011.11.17
std::remove_if ....  (0) 2011.11.06
image 포맷 변환.  (0) 2011.11.04
ImageCodecInfo Class  (0) 2011.11.04
GetImageEncoders Function  (0) 2011.11.04
Posted by 촌돌애비
TAG stl, vc++

댓글을 달아 주세요

개인적으로 STL Container를 이용한 동적할당을 자주 사용하는 편이다.

데이터의 수정과 복사등에 편리하기 때문이다.

그러나 삭제시 매번 Loop를 돌아서 참 귀찮았다..

그래서 그 항목들을 모아봤다.

// 이렇게 삭제 대상을 모아놓고...
typedef struct _rmv_stl_inst{
public:
_rmv_stl_inst(void){}
void operator() (LP_TMA_OWNSHIP_INFO& _val) { delete _val; }
void operator() (LP_TMA_TRACKING_INFO& _val) { delete _val; }
}_RMV_STL_INST;

// 이렇게 호출해 버린다...
std::for_each( m_vecOwnshipHistory.begin(), m_vecOwnshipHistory.end(), _RMV_STL_INST() );


혹은.. 
class U2INTERFACEDll _AGRTM_RMV_STL_INSTANCE{
public:
_AGRTM_RMV_STL_INSTANCE(void){}
void operator() (LP_TIF_TRACKING_INFO& _val) { delete _val; } // TrackingInfo
void operator() (LP_TIF_SENSOR_INFO& _val) { delete _val; } // SensorInfo
void operator() (LP_TIF_OWNSHIP_INFO& _val) { delete _val; } // OwnshipInfo
void operator() (LP_TIF_TGT_DROP_INFO& _val) { delete _val; } // Tartget DropInfo

void operator() (LP_RCV_SCANSET_STC& _val) { delete _val; } // ScanSet
void operator() (LP_RCV_SCANSET_DYN& _val) { delete _val; } // ScanSet
void operator() (LP_TRACKING_SCANSET& _val) { delete _val; } // ScanSet
};

이렇게 선언해 놓고... 사용하기도 하고..
std::for_each(
m_vecOwnshipHistory.begin(),
m_vecOwnshipHistory.end(), 
_AGRTM_RMV_STL_INSTANCE()
);

 아예 람다를 쓰기도 한다.
 if( m_vecTrackingHistory.empty() == false ){
std::for_each( 
m_vecTrackingHistory.begin(), 
m_vecTrackingHistory.end(), 
[](LP_TMA_TRACKING_INFO& _val){ delete _val; }
);
m_vecTrackingHistory.clear();
}

Posted by 촌돌애비

댓글을 달아 주세요


 // 람다정의
 auto fnLambdaFind = [&nData]( std::map<UINT, INT>::value_type const& itr )->bool{ 
   return nData == itr.second ? true : false;
 };

 // 입력한 nData에 해당하는 것을 map에서 찾기 찾기
 std::map<UINT, INT>::iterator it = std::find( m_mapData.begin(), m_mapData.end(), fnLambdaFind);

Posted by 촌돌애비

댓글을 달아 주세요

티스토리 툴바