경험 총결: 구조적 데이터 정렬 방식이 맵에 대한find의 영향
VC++ 2010
2 현상 묘사
2.1 구조 정의
/** */
typedefstruct tagNODE_QUERY_CONDITION
{
tagNODE_QUERY_CONDITION(DWORD nodeType,DWORD nodeId,bool includeChild, DWORDchildDepth, bool includeData)
{
this->nodeType= nodeType;
this->nodeId = nodeId;
this->includeChild= includeChild;
this->childDepth= childDepth;
this->includeData= includeData;
}
booloperator < (tagNODE_QUERY_CONDITION const& condition) const
{
returnmemcmp(this, &condition,sizeof(condition)) < 0;
}
booloperator == (tagNODE_QUERY_CONDITION const& condition) const
{
returnmemcmp(this, &condition,sizeof(condition))== 0;
}
DWORD nodeType;
DWORD nodeId;
boolincludeChild;
DWORD childDepth;
boolincludeData;
}NODE_QUERY_CONDITION;
2.2 사용 시 문제점
클래스에서 다음과 같은 구성원 변수를 정의했지만 다음 코드에서 auto it = m 발견queryBuffer.find(condition);,같은 인덱스는 Debug 버전에서 대응하는 item을 찾을 수 있으며,release 모드에서는 찾을 수 없습니다.
typedefstd::map CQueryBuffer;
CQueryBuffer m_queryBuffer;
그리고 다음과 같은 방법에서 사용한다
void CPecNodeManagerDataQuerier::QueryData()
{
CSingleLock lockQueue(&m_csQueue);
if(!lockQueue.Lock())
return;
if(m_queryQueue.empty())
return;
CSingleLocklockBuffer(&m_csQueryBuffer);
if(!lockBuffer.Lock())
return;
while(!m_queryQueue.empty())
{
tagNODE_QUERY_CONDITION condition =m_queryQueue.front();
m_queryQueue.pop_front();
CSetupNodeList nodeList;
if(ReadSetupNodesByNodeTypeID(condition.nodeType,condition.nodeId, condition.includeChild, condition.childDepth, condition.includeData,nodeList))
{
auto it = m_queryBuffer.find(condition);
if(it!= m_queryBuffer.end())
{
ASSERT(FALSE);
CSetupNodeList& nodeList =it->second;
CPublicFuncs::destroy_range(nodeList.begin(),nodeList.end());
nodeList.clear();
}
m_queryBuffer[condition] = nodeList;
}
}
}
3 원인 분석
우선 vc 컴파일러에 문제가 있는 거 아닐까요?그러나 곧 이런 가능성을 배제할 것이다. 마이크로소프트가 이렇게 저급한 실수를 범할 수는 없다.
그리고 debug버전과release버전이 어떤 차이가 있는지 고려해야 한다. 가장 뚜렷한 차이점은 debug버전은 분배된 메모리를 초기화하고release버전은 그렇지 않다는 것이다.
이 예와 결합하면 맵의find를 사용했기 때문에find의 실현은tagNODE에 의존한다QUERY_CONDITION 의 = = 및
그리고 또 tagNODE를 보러...QUERY_CONDITION 구조의 이 두 연산자의 실현은 코드가 다음과 같다. 이런 비교적 게으른 방법은 어떻게 보면 좀 이상하다고 생각하지만 이해할 수 있다.
booloperator < (tagNODE_QUERY_CONDITION const& condition) const
{
returnmemcmp(this, &condition,sizeof(condition)) < 0;
}
booloperator == (tagNODE_QUERY_CONDITION const& condition) const
{
returnmemcmp(this, &condition,sizeof(condition))== 0;
}
그리고sizeof를 의심하기 시작했어요. 이게 되돌아오는 수치가 얼마예요?그리고 다시 보면 이 구조의 구성원 중 두 개의 bool이 있는데 32비트 또는 64비트 시스템에서 이 구조가 촘촘한 저장소를 사용하지 않으면 이 구조 대상이 차지하는 메모리가 실제 필요한 메모리보다 많다. 예를 들어 이 구조에 대해sizeof는 16으로 되돌아간다. 비록 실제로는 14만 필요하지만.
4 해결 방법
위의 분석에 따라 구조 정의를 수정하고 구조 앞뒤에 추가합니다.
#pragma pack(1)
…..
#pragma pack()
다시 컴파일한 후,release에서 대응하는item을 찾을 수 있습니다.
한층 더 분석하면return memcmp(this, &condition,sizeof(condition)<0;이런 실현 방식은 사실 결함이 있다. 예를 들어 나중에 구조를 바꾸는 데 더블 형식의 데이터 구성원을 추가하면 여기에서 되돌아오는 구조는 우리가 원하는 것이 아닐 수도 있다.
그래서 이 비교 방법을 정규적인 방식에 따라 실현하는 것을 건의한다. 예를 들어 다음과 같다.
bool operator < (tagNODE_QUERY_CONDITION const& condition)const
{
If(this.nodeType < condition.nodeType)
returntrue;
else if(this.nodeId < condition.nodeId)
returntrue;
else if(this.includeChild< condition.includeChild)
returntrue;
elseif(this.childDepth < condition.childDepth)
returntrue;
else if(this.includeData < condition.includeData)
returntrue;
returnfalse;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
기술 비망록의 7VC에서 파일 읽기와 쓰기 오늘 몇 시간 동안 파일의 봉인 클래스인 CFileUtils를 써서 다중 디렉터리를 만들 수 있습니다.ini 파일의 읽기와 쓰기 및 기타 파일의 읽기와 쓰기, 빨리 코드를 붙여서 잊어버리지...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.