2014-10-06 3 views
4

우리 프로젝트에서 신비로운 문제를 발견 한 후에도 여전히 충격을 받았습니다.C++ rapidjson : GenericValue :: IsNull은 어떤 경우에도 false를 반환합니다.

HasMember ("string")를 호출하면 추가 검색이 수행된다는 것을 알았습니다. 따라서 성능상의 이유로 변경합니다.

주요 아이디어는 다음과 같습니다에 변경

rapidjson::Document d; 
d.Parse<0>(json); 

if(d.HasMember("foo")) 
{ 
    const rapidjson::Value& fooValue = d["foo"]; 

    // do something with fooValue 
} 

: HasMember를 호출하고 이후에 같은 기준을 미리 캐시의 대신

이 제법 괜찮은

rapidjson::Document d; 
d.Parse<0>(json); 

const rapidjson::Value& fooValue = d["foo"]; 
if(!fooValue.IsNull()) 
{ 
    // do something with fooValue 
} 

, 우리는 수행하기 위해 저장 단 하나가 아닌 두 번 추구한다. 그러나 여기에 문제가 있습니다. rapidjson이 (실패 추구 때 기본적으로 반환)에 nullValue를 구현하는 방법은 다음과 같은 코드를 볼 수 있습니다 찾고 시작하면

는 : 멤버를 찾을하지 않은 경우

//! Get the value associated with the object's name. 
GenericValue & operator[](const Ch* name) { 
    // Check 
    if (Member * member = FindMember(name)) { 
     return member->value; 
    } else { 
     // Nothing 
     static GenericValue NullValue; 
     return NullValue; 
    } 
} 

// Finder 
const GenericValue & operator[] (const Ch* name) const { 
    // Return 
    return const_cast<GenericValue &> (* this)[name]; 
} 

그래서, 우리는 지역 정적 변수를 반환합니다. 이것은 언뜻보기에 충분할 것 같지만 참조로 돌아 오기 때문에 숨겨진 버그가 생길 수 있습니다.

누군가 정적 NullValue의 참조를 변경한다고 상상해보십시오. 이로 인해 NullValue가 다른 유형으로 변경되었거나 임의의 메모리로 변경 되었기 때문에 IsNull을 찾는 이후의 모든 추가 호출이 실패합니다.

그래서, 너 뭐야? 이 패턴이 좋은 null 패턴이라고 생각하십니까?

혼란 스럽습니다. 기본 null 값을 반환한다는 생각은 좋아하지만 const로 반환되지 않았으므로 위험합니다. 그리고 우리가 const로 모든 경우에 그것을 반환하더라도, devs는 여전히 const_cast를 사용할 수 있습니다. (그렇다고하더라도 그렇게한다면 책임을지지 않습니다.)

나는이 사례와 다른 사례를 듣고 싶습니다. 그리고 누군가 rapidjson 코드 아래서 진짜 해결책을 줄 수 있다면 근본적으로 멋지고 놀랍습니다.

+1

'if (! d.IsNull())'이 (가) if (! fooValue.IsNull())이어야합니다. – Narek

+0

오른쪽! 수정되었습니다. – dmayola

답변

6

이 디자인의 함정은 오래전에 커뮤니티에 의해 제기되었습니다. operator[]도 비 const 버전이 필요하기 때문에 정적 변수의 무결성을 유지하는 것은 불가능합니다.

이 API는 새로운 버전의 RapidJSON에서 변경되었습니다. operator[]은 존재하지 않는 키를 단순히 어설트합니다. 이 키가 존재하는 것이 확실이면 바람직

MemberIterator FindMember(const Ch* name); 
ConstMemberIterator FindMember(const Ch* name) const; 

를 이용하여 키가 존재 하는지를 확인 MemberEnd()과 값을 비교한다. 또한 here에 설명되어 있습니다.

또한 RapidJSON이 GitHub으로 이동되었습니다. 많은 문제가 해결되었습니다. 가능한 경우 최신 버전을 사용하십시오. 고맙습니다.

P. 나는 RapidJSON의 저자이다.

+0

마일로 어디에서 rapidjson 0.2 버전을 찾을 수 있습니까? – Narek