검색 결과를 찾을 수없는 경우 "NULL"개체를 반환합니다.


94

저는 C ++를 처음 접하기 때문에 배우는 동안 많은 Java-ism으로 디자인하는 경향이 있습니다. 어쨌든 Java에서 특정 매개 변수와 일치 하는 객체 T를 반환하는 'search'메서드가있는 클래스가 Collection< T >있으면 해당 객체를 반환하고 객체가 컬렉션에서 발견되지 않으면 null. 그런 다음 내 호출 함수에서if(tResult != null) { ... }

C ++ null에서 객체가 존재하지 않으면 값을 반환 할 수 없다는 것을 알게되었습니다 . 호출 함수에 개체가 없음을 알리는 T 유형의 '인디케이터'를 반환하고 싶습니다. 정말 예외적 인 상황이 아니기 때문에 예외를 던지고 싶지 않습니다.

지금 내 코드는 다음과 같습니다.

class Node {
    Attr& getAttribute(const string& attribute_name) const {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return NULL; // what should this be?
    }

private:
    vector<Attr> attributes;
}

그런 종류의 마커를 줄 수 있도록 어떻게 변경할 수 있습니까?


6
예외와 NULL이 항상 유일한 해결책은 아닙니다. 찾을 수 없음을 나타내는 반환 할 값을 선택할 수 있습니다. 예를 들어 일치하는 요소가 없으면 std::find(first, last, value)반환 last합니다.
Cascabel

답변:


70

C ++에서 참조는 null 일 수 없습니다. 아무것도 발견되지 않은 경우 선택적으로 null을 반환하려면 참조가 아닌 포인터를 반환해야합니다.

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return nullptr;
}

그렇지 않고 참조로 반환을 고집하면 속성을 찾을 수 없으면 예외를 throw해야합니다.

(그런데, 당신의 메서드가 constconst속성을 반환하는 것에 대해 약간 걱정 됩니다. 철학적 인 이유로를 반환하는 것이 좋습니다 const Attr *.이 속성을 수정하려는 경우에도 비 const메서드로 오버로드 할 수 있습니다. 비 const속성도 반환합니다 .)


2
감사. 그건 그렇고, 이것이 그러한 루틴을 디자인하는 데 허용되는 방법입니까?
aduric 2010

6
@aduric : 네. 참조는 결과가 존재해야 함을 의미합니다. 포인터는 결과가 존재하지 않을 수 있음을 의미합니다.
Bill

7
궁금한 점이 있습니다. 이제 c ++ 11 nullptr대신 돌아 올까요 NULL?
Spectral 2014

1
yes는 항상 C ++ 11 이상에서 NULL보다 nullptr을 사용합니다. 당신이 earliver 버전과 이전 버전과 호환되도록해야하는 경우 다음하지 않습니다
콘라드 존스

56

여기에 몇 가지 가능한 답변이 있습니다. 존재할 수있는 것을 반환하고 싶습니다. 다음은 가장 선호하지 않는 것부터 가장 선호하는 것까지 몇 가지 옵션입니다.

  • 참조로 반환하고 예외로 찾을 수 없음 신호를 보냅니다.

    Attr& getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            throw no_such_attribute_error;
    }

속성을 찾지 못하는 것은 실행의 정상적인 부분이므로 예외는 아닙니다. 이에 대한 처리는 시끄 럽습니다. null 참조를 갖는 것은 정의되지 않은 동작이므로 null 값을 반환 할 수 없습니다.

  • 포인터로 반환

    Attr* getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return &attributes[i];
       //if not found
            return nullptr;
    }

getAttribute의 결과가 NULL이 아닌 포인터인지 확인하는 것은 잊기 쉽고 버그의 쉬운 원인입니다.

  • Boost를 사용하십시오 .

    boost::optional<Attr&> getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return boost::optional<Attr&>();
    }

boost :: optional은 여기서 무슨 일이 일어나고 있는지 정확하게 나타내며 그러한 속성이 발견되었는지 여부를 검사하는 쉬운 방법을 가지고 있습니다.


참고 : std :: optional은 최근 C ++ 17에 투표되었으므로 가까운 장래에 "표준"이 될 것입니다.


+1 먼저 boost :: optional을 먼저 언급하고 다른 대안을 간략히 언급합니다.
Nemanja Trifunovic

Ya 나는 boost :: optional이 어딘가에 언급 된 것을 보았지만 너무 많은 오버 헤드가 필요하다고 생각했습니다. 사용하는 것이 이러한 종류의 문제에 대한 최선의 방법이라면 사용을 시작하겠습니다.
aduric 2010

boost::optional오버 헤드가 많지 않기 때문에 (동적 할당 없음) 이것이 매우 큰 이유입니다. 다형성 값과 함께 사용하려면 래핑 참조 또는 포인터가 필요합니다.
Matthieu M.

2
@MatthieuM. Aduric이 언급 한 오버 헤드는 성능이 아니라 프로젝트에 외부 라이브러리를 포함하는 비용 일 가능성이 높습니다.
Swoogan

내 대답에 대한 부록 : C ++ 17이 될 수있는 표준 구성 요소로 선택 사항을 표준화하는 움직임이 있음을 유의하십시오. 따라서이 기술에 대해 아는 것이 좋습니다.
Kaz Dragon

22

NULL 반환을 나타내는 정적 개체를 쉽게 만들 수 있습니다.

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

그리고 소스 파일 어딘가에 :

static Attr AttrNull;

NodeNull은 Attr 유형이 아니어야합니까?
aduric 2010


2

Java (또는 C #)에서했던 방식으로는 할 수 없다는 것을 알고 있습니다. 여기에 또 다른 제안이 있습니다. 객체의 참조를 인수로 전달하고 bool 값을 반환 할 수 있습니다. 컬렉션에서 결과가 발견되면 전달되는 참조에 할당하고 'true'를 반환하고 그렇지 않으면 'false'를 반환 할 수 있습니다. 이 코드를 고려하십시오.

typedef std::map<string, Operator> OPERATORS_MAP;

bool OperatorList::tryGetOperator(string token, Operator& op)
{
    bool val = false;

    OPERATORS_MAP::iterator it = m_operators.find(token);
    if (it != m_operators.end())
    {
        op = it->second;
        val = true;
    }
    return val;
}

위의 함수는 '토큰'키에 대해 연산자를 찾아야합니다. 만약 그것이 참을 반환하는 것을 찾으면 매개 변수 연산자 & op에 값을 할당합니다.

이 루틴의 호출자 코드는 다음과 같습니다.

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}

1

여기서 NULL을 반환 할 수없는 이유는 반환 유형을 Attr&. 후행 &은 반환 값을 "참조"로 만듭니다. 이는 기본적으로 기존 개체에 대한 null이 될 수 없음을 보장하는 포인터입니다. null을 반환하려면 Attr&로 변경 하십시오 Attr*.


0

당신은 반환 할 수없는 NULL함수의 반환 형식은 객체이기 때문 reference이지 pointer.


-3

이것을 시도 할 수 있습니다.

return &Type();

6
이 코드 스 니펫은 질문을 해결할 수 있지만 설명을 포함하면 게시물의 품질을 개선하는 데 실제로 도움이됩니다. 앞으로 독자를위한 질문에 답하고 있으며, 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
NathanOliver 2015

이것은 아마도 메서드 스택의 객체에 대한 죽은 참조를 반환 할 것입니다.
mpromonet 2015
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.