문제

큰 C ++ 코드베이스를 상속했으며 코드베이스에서 발생할 수있는 널 포인터 예외를 피하는 작업이 있습니다. 사용 가능한 정적 분석 도구가 있습니까? 나는 당신이 성공적으로 사용했다고 보풀을 생각하고 있습니다.

당신은 다른 것들을 찾고 있습니까?

도움이 되었습니까?

해결책

Null 소스를 제거하여 시작할 수 있습니다.

변화

if (error) {
    return NULL;
}

안으로

if (error) {
    return DefaultObject; // Ex: an empty vector
}

반환 기본 오브젝트가 적용되지 않고 코드베이스가 이미 예외를 사용하는 경우

if (error) {
    throw BadThingHappenedException;
}

그런 다음 적절한 장소에서 처리를 추가하십시오.

레거시 코드로 작업하는 경우 일부 래퍼 기능/클래스를 만들 수 있습니다.

ResultType *new_function() {
    ResultType *result = legacy_function();
    if (result) {
        return result;
    } else {
        throw BadThingHappenedException;
    }
}

새로운 기능은 새로운 기능을 사용하기 시작하고 적절한 예외 처리가 있어야합니다.

나는 일부 프로그래머가 똑똑한 사람들을 포함하여 예외를 얻지 못한다는 것을 알고 있습니다. 조엘. 그러나 Null을 반환함으로써 일어나는 일은이 널이 미친 듯이 지나가는 것입니다. 모든 사람들이 그것을 처리하고 조용히 돌아 오는 것이 그들의 사업이 아니라고 생각하기 때문입니다. 일부 기능은 오류 코드를 반환 할 수 있습니다. 이는 괜찮습니다. 그러나 발신자는 종종 오류에 대한 응답으로 아직도 반환됩니다. 그런 다음 기능이 얼마나 사소한 지에 관계없이 모든 단일 함수에서 많은 널 체크를 볼 수 있습니다. 그리고 필요한 것은 NULL이 프로그램을 충돌시키지 않는지 하나의 장소 일뿐입니다. 예외는 오류에 대해 신중하게 생각하고 어디에서, 어떻게 처리 해야하는지 정확하게 결정해야합니다.

정적 분석 도구 (항상 사용해야 함)와 같은 쉬운 솔루션을 찾고있는 것 같습니다. 포인터를 참조로 변경하는 것도 훌륭한 솔루션입니다. 그러나 C ++는 RAII의 아름다움을 가지고있어 "Try {{} 최종적으로 {}"가 어디에서나 필요하지 않으므로 진지하게 고려해야 할 가치가 있다고 생각합니다.

다른 팁

주로 코드베이스를 유지하는 경우 가장 낮은 수준의 효율성 중 하나이며 가장 높은 수익률 중 하나는 베어 포인터를 다시 연락하는 것입니다. 참조 계수 포인터.

나는 또한 같은 것을 볼 것입니다 정화하십시오 코드가 메모리 손상을 감지하는 데 도움이됩니다.

첫째, 기술적 인 점으로 C ++에는 Null 포인터 예외가 없습니다. 널 포인터를 사용하지 않으면 정의되지 않은 동작이 있으며 대부분의 시스템에서 프로그램이 갑자기 종료됩니다 ( "충돌").

도구에 관해서는 다음과 같은 질문을 권장합니다.

C ++ 정적 코드 분석 도구가 그만한 가치가 있습니까?

특히 Null 포인터 피해와 관련하여 Null 포인터 Dereference에는 세 가지 주요 요소가 있다고 생각합니다.

  1. 널 포인터의 도입.
  2. 프로그램의 다른 곳에서 그 포인터의 흐름.
  3. 그 포인터의 불평.

정적 분석 도구의 어려운 부분은 물론 2 단계이며, 도구는 그들이 너무 많은 오 탐지없이 정확하게 (즉, 너무 많은 오 탐지없이) 경로가 얼마나 복잡한 지에 따라 차별화됩니다. 어떤 종류의 도구가 가장 효과적인지 더 잘 조언하기 위해 잡고 싶은 버그의 구체적인 예를 보는 것이 유용 할 수 있습니다.

면책 조항 : 나는 은폐를 위해 일합니다.

코드를 변경하지 않으려면 일부 도구를 사용해야합니다 (다른 답변 참조). 그러나 문제의 특별한 부분 (사용 기능에 포인터를 넣는 곳)의 경우, 약간의 버거를 찾는 데 사용할 수있는 멋진 작은 makro 정의가 있습니다. 코드 조건)

    #ifdef  NDEBUG

    #define NotNull(X) X

    #else // in Debug-Mode

    template<typename T> class NotNull;

    template<typename T> // template specialization only for pointer-types
    class NotNull<T*> {
    public:
        NotNull(T* object)
        : _object(object) {
            assert(object);
        }

        operator T*() const {
            return _object;
        }

        T* operator->() const {
            return _object;
        }
    private:
        T *_object;
    };

    #define NotNull(X) NotNull<X>

    #endif // in Debug-Mode

당신은 이것으로 모든 기능을 변경합니다.

void increase(int* counter)  
{ .. } 

이에

void increase(NotNull(int*) counter)
{ .. }  

추신 : 처음 발견되었습니다 여기 더욱 조정할 수 있습니다

부수적 인 질문은 고객이 충돌을보고 싶지 않기 때문에이를 피하는 목적입니까? 많은 경우 널 포인터는 즉시 처리 해야하는 예기치 않은 조건이지만 너무 자주 고구마처럼 시스템을 통해 통과됩니다.

나는 한때 습관이 함수에 들어갔을 때 코드베이스에서 일하고, 먼저 널 포인터를 확인하고 그렇다면 다시 돌아 왔습니다. 이것의 문제점은 도구가 충돌하지 않았지만 궁극적으로 불량 데이터가 조용히 생성된다는 것입니다. 그리고 이러한 문제를 디버깅하려고 시도하는 것은 불법적으로 널리 포인터가 오랫동안 통과되어 많은 기능을 통해 결과가 참을 수 없거나 궁극적으로 자체적으로 나타나기 전에 어려웠 기 때문에 어려웠습니다.

이상적으로, 당신은 최소한 개발 기간 동안 적절한 주장을 원하므로 매크로를 고려하여 생산 빌드에 대한 어설 션을 숨기거나 재정의하는 것을 고려하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top