문제

가능한 중복:
방어 프로그램

우리는 좋은 토론이 아침의 주제에 대해 방어 프로그램입니다.우리는 코드를 검토하는 포인터에서 통과되었다고 선택하지 않은 경우 유효합니다.

어떤 사람을 느꼈다는 것만 확인 null 포인터가 필요했습니다.내가 의문을 제기하는지 확인할 수 있습 높은 수준에서,보다는 오히려 모든 방법을 통해 전달되고 있는 검사에 대한 null 었고 매우 제한적인 경우에는 개체에서의 다른 쪽 끝 지점을 만족하지 않았다 특정 요구 사항이 있습니다.

내가 이해하고 동의하는 확인 null 이 아무것보다는 더 낫지만,그것은 느낌을 내는 검사에 대해서만 null 이 제공하는 보안의 잘못된 인식기 때문에 제한된 범위가 있습니다.당신이 원하는지 확인하는 포인터를 사용할 수 있는지 확인,보다 더 많은 null 입니다.

여러분은 어떤 경험을 하셨나요?니다.당신은 어떻게 쓰기 방어에서 당신의 코드를 매개변수를 위한 전달되는 하위 방법?

도움이 되었습니까?

해결책

Code Complete 2에서 오류 처리에 관한 장에서 바리케이드 아이디어를 소개했습니다. 본질적으로, 바리케이드는 모든 입력을 엄격하게 검증하는 코드입니다. 바리케이드 내부의 코드는 잘못된 입력이 이미 처리되었으며 수신 된 입력이 양호하다고 가정 할 수 있습니다. Barricade 내부에서 코드는 Barricade 내의 다른 코드로 전달 된 잘못된 데이터에 대해서만 걱정하면됩니다. 조건과 신중한 단위 테스트를 주장하면 Barricaded 코드에 대한 신뢰가 높아질 수 있습니다. 이런 식으로, 당신은 바리케이드에서 매우 방어 적으로 프로그램하지만 바리케이드 내부에서는 덜 프로그램됩니다. 그것에 대해 생각하는 또 다른 방법은 Barricade에서 항상 오류를 올바르게 처리하고 Barricade 내부에서는 디버그 빌드에서 조건을 주장하는 것입니다.

원시 포인터를 사용하는 한, 일반적으로 최선을 다하면 포인터가 널이 아니라고 주장하는 것입니다. 그 기억에 무엇이 있는지 알고 있다면 내용이 어떤 식 으로든 일관되도록 할 수 있습니다. 이것은 왜 그 메모리가 일관성 자체인지 확인할 수있는 객체에 메모리가 싸여 있지 않은지에 대한 의문을 제기합니다.

그렇다면 왜이 경우 원시 포인터를 사용하고 있습니까? 참조 나 스마트 포인터를 사용하는 것이 더 낫습니까? 포인터에는 숫자 데이터가 포함되어 있으므로 해당 포인터의 수명주기를 관리하는 객체에 마무리하는 것이 더 좋습니다.

이러한 질문에 답하면 방어하기 쉬운 디자인으로 끝날 수 있다는 점에서 더 방어적인 방법을 찾는 데 도움이 될 수 있습니다.

다른 팁

방어적인 가장 좋은 방법은 런타임에서 NULL 포인터를 확인하는 것이 아니라 처음부터 무효가 될 수있는 포인터 사용을 피하십시오.

통과되는 물체가 무효가되어서는 안되는 경우 참조를 사용하십시오! 또는 가치로 통과하십시오! 또는 어떤 종류의 스마트 포인터를 사용하십시오.

방어 프로그래밍을 수행하는 가장 좋은 방법은 컴파일 타임에 오류를 포착하는 것입니다. 객체가 무효가되거나 쓰레기를 가리키는 오류로 간주되면, 그러한 것들이 오류를 컴파일해야합니다.

궁극적으로, 포인터가 유효한 개체를 가리키는 지 알 수있는 방법이 없습니다. 확인하기보다는 하나 특정 코너 케이스 (실제로 위험한 것보다 훨씬 덜 일반적인 경우, 유효하지 않은 개체를 가리키는 포인터)는 유효성을 보장하는 데이터 유형을 사용하여 오류를 불가능하게 만듭니다.

C ++만큼 컴파일 타임에서 많은 오류를 잡을 수있는 또 다른 주류 언어를 생각할 수 없습니다. 그 기능을 사용하십시오.

포인터가 유효한지 확인할 방법이 없습니다.

진지하게, 그것은 당신이 당신에게 가질 수있는 버그 수에 달려 있습니다.

널 포인터를 확인하는 것은 확실히 필요하지만 충분하지 않은 것입니다. 코드의 진입 점에서 시작하여 사용할 수있는 다른 견고한 원칙이 많이 있습니다 (예 : 입력 유효성 검사 = 해당 포인터가 유용한 것을 포인트하는 것) 및 종료 지점 (예 : 포인터가 유용한 것을 가리 켰다고 생각했지만 원인이 발생했다고 생각했습니다. 예외를 던지기위한 코드).

요컨대, 코드를 부르는 모든 사람이 당신의 삶을 망치기 위해 최선을 다할 것이라고 가정하면 아마도 최악의 범인을 많이 찾을 것입니다.

명확성 편집 : 다른 답변은 단위 테스트에 대해 이야기하고 있습니다. 나는 테스트 코드가 때때로 있다고 굳게 믿는다 테스트중인 코드보다 유용합니다 (값을 측정하는 사람에 따라). 즉, 나는 또한 단위 테스트가 또한 방어 코딩에는 필요하지만 충분하지 않습니다.

구체적인 예 : 요청과 일치하는 값 모음을 반환하도록 기록 된 타사 검색 방법을 고려하십시오. 불행히도, 해당 방법에 대한 문서에서 명확하지 않은 것은 원래 개발자가 요청과 일치하지 않으면 빈 컬렉션보다는 널을 반환하는 것이 더 낫다고 결정했다는 것입니다.

이제, 당신은 방어적이고 잘 테스트 한 방법 사고 (슬프게도 내부 널 포인터 점검이 부족함)와 붐이라고 부릅니다! NullPointerException 내부 점검이 없으면 다음을 처리 할 방법이 없습니다.

defensiveMethod(thirdPartySearch("Nothing matches me")); 
// You just passed a null to your own code.

나의 팬이라면"그것이 충돌하"학교의 디자인이다.(면책 조항:지 않아요 작업에서 의료 기기,항공,또는 원자력 관련 소프트웨어입니다.) 하는 경우 프로그램으로 불면,당신은 불 디버거와습니다.에 대비하는 경우,프로그램을 유지한 후 실행 불법 매개 변수가 감지되는 시간에 의해 충돌 당신은 아마 아무 생각이 무엇을 잘못했습니다.

좋은 코드의 구성은 많은 작은 기능을 메고 다스 라인의 매개변수 검사하여 모든 하나의 조각의 코드를 어렵게 읽고 유지하기 어렵습니다.단순하게 유지합니다.

나는 약간 극단적 일지 모르지만 방어 프로그래밍을 좋아하지 않습니다. 원칙을 소개 한 게으름이라고 생각합니다.

이 특별한 예에서는 포인터가 무효가 아니라고 주장하는 것은 의미가 없습니다. 널 포인터를 원한다면 참조를 사용하는 것보다 실제로 시행하고 동시에 명확하게 문서화하는 더 좋은 방법은 없습니다. 그리고 그것은 실제로 컴파일러가 시행하고 런타임에 Ziltch의 비용이 들지 않는 문서입니다!

일반적으로 '원시'유형을 직접 사용하지 않는 경향이 있습니다. 설명하자 :

void myFunction(std::string const& foo, std::string const& bar);

가능한 값은 무엇입니까? foo 그리고 bar ? 글쎄, 그것은 무엇에 의해서만 제한적입니다. std::string 포함 할 수 있습니다 ... 꽤 모호합니다.

반면에:

void myFunction(Foo const& foo, Bar const& bar);

훨씬 낫다!

  • 사람들이 잘못된 인수 순서를 실수로 뒤집는 경우 컴파일러에 의해 감지됩니다.
  • 각 클래스는 값이 옳고 사용자가 부담하지 않은지 확인하는 데 책임이 있습니다.

나는 강력한 타이핑을 선호하는 경향이 있습니다. 알파벳 캐릭터로만 구성되어야하고 최대 12 자까지 작용하는 항목이 있다면, 작은 클래스 포장을 만들고 싶습니다. std::string, 단순한 validate 방법은 내부적으로 과제를 확인하고 대신 해당 클래스를 통과했습니다. 이렇게하면 검증 루틴을 한 번 테스트하면 해당 값이 나에게 얻을 수있는 모든 경로에 대해 실제로 걱정할 필요가 없다는 것을 알고 있습니다.> 그것이 나에게 도달하면 검증 될 것입니다.

물론 코드를 테스트해서는 안된다는 것은 아닙니다. 그것은 단지 강력한 캡슐화를 선호하며 입력의 검증은 제 생각에 지식 캡슐화의 일부입니다.

그리고 예외없이 규칙이 올 수 없으므로 ... 노출 된 인터페이스는 반드시 유효성 검사 코드로 부풀어 오릅니다. 그러나 당신의 BOM에서 자체 검색 물체를 사용하면 일반적으로 매우 투명합니다.

"코드를 검증하는 단위 테스트는해야 할 일을 수행해야합니다"> "제작 코드가하지 말아야 할 일을 수행하지 않으려 고 노력합니다".

출판 된 API의 일부가 아니라면 Null을 확인하지도 않을 것입니다.

그것은 매우 달라집니다. 문제의 메소드가 그룹 외부 코드에 의해 호출 되었습니까? 아니면 내부 방법입니까?

내부 방법의 경우, 이것을 무시 지점으로 만들기에 충분히 테스트 할 수 있으며, 목표가 가장 높은 성능 인 코드를 작성하는 경우 입력을 확인하는 데 시간을 보내고 싶지 않을 수 있습니다.

외부 가시적 인 방법의 경우 (있는 경우) 항상 입력을 두 번 확인해야합니다. 언제나.

디버깅 관점에서 코드가 빠른 경우 가장 중요합니다. 코드가 일찍 실패할수록 실패 지점을 쉽게 찾을 수 있습니다.

내부 방법의 경우, 우리는 일반적으로 이러한 종류의 수표에 대한 주장을 고수합니다. 그것은 단위 테스트 (당신이 좋은 테스트 범위, 맞습니까?) 또는 적어도 어설 션과 함께 실행되는 통합 테스트에서 오류가 발생합니다.

널 포인터 확인 ~이다 이야기의 절반 만, 당신도해야합니다 할당되지 않은 모든 포인터에 널 값을 할당하십시오.
대부분의 책임있는 API는 동일하게 수행합니다.
널 포인터를 확인하는 것은 CPU주기에서 매우 저렴하며, 전달 된 후에 응용 프로그램이 충돌하면 회사와 회사가 돈과 명성으로 비용이들 수 있습니다.

코드가 비공개 인터페이스에있는 경우 NULL 포인터 점검을 건너 뛸 수 있습니다. 단위 테스트 또는 일부 디버그 빌드 테스트 (예 : Assert)를 실행하여 완전히 제어하고/또는 NULL을 확인하십시오.

이 질문에는 내가 다루고 싶은 몇 가지가 있습니다.

  1. 코딩 가이드 라인은 포인터를 사용하는 대신 참조 또는 값을 직접 처리하도록 지정해야합니다. 정의에 따르면, 포인터는 메모리에서 주소를 보유하는 값 유형입니다. 포인터의 유효성은 플랫폼에 따라 다르며 많은 것을 의미합니다 (주소 지정 가능한 메모리, 플랫폼 등의 범위).
  2. 어떤 이유로 든 (동적으로 생성되고 다형성 객체와 같은) 스마트 포인터를 사용하는 것을 고려하십시오. 스마트 포인터는 "정상적인"포인터의 의미론으로 많은 장점을 제공합니다.
  3. 예를 들어 유형에 "유효하지 않은"상태가 있으면 유형 자체가이를 제공해야합니다. 보다 구체적으로, "불법 정의 된"또는 "이니셜 화 된"객체 (예외를 던지거나 NO-OP 멤버 함수를 제공함으로써)를 지정하는 nullobject 패턴을 구현할 수 있습니다.

NullObject 기본값을 수행하는 스마트 포인터를 만들 수 있습니다.

template <class Type, class NullTypeDefault>
struct possibly_null_ptr {
  possibly_null_ptr() : p(new NullTypeDefault) {}
  possibly_null_ptr(Type* p_) : p(p_) {}
  Type * operator->() { return p.get(); }
  ~possibly_null_ptr() {}
  private:
    shared_ptr<Type> p;
    friend template<class T, class N> Type & operator*(possibly_null_ptr<T,N>&);
};

template <class Type, class NullTypeDefault>
Type & operator*(possibly_null_ptr<Type,NullTypeDefault> & p) {
  return *p.p;
}

그런 다음 사용하십시오 possibly_null_ptr<> 템플릿 기본 파생 "NULL 동작"이있는 유형에 대한 널 포인터를 지원하는 경우 템플릿. 이것은 디자인에서 "널 객체"에 대한 허용 가능한 동작이 있다는 것을 명시하게 만들므로 일반 가이드 라인이나 실습보다 코드에 방어 관행을 문서화합니다.

포인터는 포인터로 무언가를 해야하는 경우에만 사용해야합니다. 포인터 산술과 같은 일부 데이터 구조를 가로 지르는 것. 가능하면 클래스에서 캡슐화해야합니다.

포인터가 함수로 전달되어 가리키는 객체로 무언가를 수행 한 다음 대신 참조로 전달하십시오.

방어 프로그래밍을위한 한 가지 방법은 가능한 거의 모든 것을 주장하는 것입니다. 프로젝트의 시작 부분에서는 성가 시지만 나중에는 단위 테스트의 좋은 부속물입니다.

여러 답변은 코드에 방어를 작성하는 방법에 대한 질문을 다루지 만 "얼마나 방어 적이어야합니까?"에 대해서는 아무 말도하지 않았습니다. 그것은 소프트웨어 구성 요소의 중요성에 따라 평가해야 할 것입니다.

우리는 비행 소프트웨어를하고 있으며 소프트웨어 오류의 영향은 경미한 성가심에서 항공기/승무원 손실에 이르기까지 다양합니다. 우리는 코딩 표준, 테스트 등에 영향을 미치는 잠재적 불리한 영향에 따라 다양한 소프트웨어 조각을 분류합니다. 소프트웨어 사용 방법과 오류의 영향을 평가하고 원하는 수준의 방어 성 (및 감당할 수있는 수준)을 설정해야합니다. 그만큼 DO-178B 표준 이것을 "디자인 보증 수준"이라고 부릅니다.

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