C에서 "소멸자"를 생략하면 YAGNI가 너무 멀리 걸리나요?


9

OO와 유사한 기술을 사용하여 C의 중간 임베디드 응용 프로그램을 작성 중입니다. 내 "클래스"는 데이터 구조체와 함수 포인터 구조체를 사용하여 캡슐화, 다형성 및 종속성 주입을 에뮬레이트하는 .h / .c 모듈입니다.

이제 myModule_create(void)함수에 myModule_destroy(pointer)대응 하는 기능 이있을 것으로 예상 됩니다. 그러나 프로젝트가 임베드되어 있으며 실제로 인스턴스화되는 리소스는 절대 공개되지 않아야합니다.

즉, 4 개의 UART 직렬 포트가 있고 필요한 핀과 설정으로 4 개의 UART 인스턴스를 만드는 경우 런타임 중에 어느 시점에서 UART # 2를 파괴 할 이유가 전혀 없습니다.

YAGNI (필요하지 않을 것입니다) 원칙에 따라 소멸자를 생략해야합니까? 이것은 나에게 매우 이상해 보이지만 나는 그것들을 사용할 생각을 할 수 없다. 장치 전원이 꺼지면 리소스가 해제됩니다.


4
객체를 처리하는 방법을 제공하지 않으면 생성 된 "무한"수명이 있다는 명확한 메시지가 전달됩니다. 이것이 귀하의 응용 프로그램에 의미가 있다면, 말합니다.
glampert

4
유형을 특정 유스 케이스에 결합하여 멀리 나아가려면 왜 myModule_create(void)기능이 있습니까? 사용하려는 특정 인스턴스를 노출하는 인터페이스에 하드 코딩 할 수 있습니다.
Doval

@Doval 나는 그것에 대해 생각했다. 저는 상사로부터 코드의 일부와 비트를 사용하는 인턴이므로 "올바른 작업"을 경험하고 경험을 위해 C에서 OO 스타일을 실험하고 회사 표준과의 일관성을 유지하려고 노력하고 있습니다.
Asics

2
@glampert는 그것을 못 박는 다; create 함수의 문서에서 기대했던 무한 수명을 깨끗하게 만들어야한다고 덧붙였습니다.
Blrfl

답변:


11

객체를 처리하는 방법을 제공하지 않으면 생성 된 "무한"수명이 있다는 명확한 메시지가 전달됩니다. 이것이 당신의 응용 프로그램에 의미가 있다면, 나는 말합니다 : 그렇게하십시오.

글램 퍼트 가 옳다. 여기에 소멸자가 필요하지 않습니다. 그들은 단지 코드 팽창과 사용자를위한 함정을 만들 것입니다 (소멸자가 호출 된 후에 객체를 사용하는 것은 정의되지 않은 동작입니다).

그러나 물체를 폐기 할 필요가 없는지 확인해야합니다. 예를 들어, 현재 사용되고 있지 않은 UART에 대한 객체가 필요합니까?


3

메모리 누수를 감지하는 가장 쉬운 방법은 응용 프로그램을 완전히 종료하는 것입니다. 많은 컴파일러 / 환경은 응용 프로그램이 종료 될 때 여전히 할당 된 메모리를 확인하는 방법을 제공합니다. 하나가 제공되지 않으면 일반적으로 종료하기 전에 코드를 추가하여 알아낼 수있는 방법이 있습니다.

따라서 임베디드 시스템에서도 생성자, 소멸자 및 셧다운 로직을 제공하여 메모리 누출을 쉽게 감지하기 위해 "이론적으로"나가지 않아야합니다. 실제로 응용 프로그램 코드를 종료해서는 안되는 경우 메모리 누수 감지가 훨씬 중요합니다.


할당하는 유일한 시간이 시작하는 동안에 만 적용되는 것은 메모리 제한 장치에서 심각하게 고려해야 할 패턴입니다.
코드 InChaos

@Codes : 자신을 제한 할 이유가 없습니다. 스타트 업시 메모리를 사전 할당하는 훌륭한 디자인을 고안 할 수 있지만,이 위대한 계획에 관심이 없거나 중요하지 않은 사람들과 함께 온 사람들은 메모리에 메모리를 할당하게됩니다. 비행하면 디자인이 진행됩니다. 올바르게하고 할당 / 할당 해제하고 구현 한 것이 실제로 작동하는지 확인하십시오. 메모리가 제한된 장치를 가지고 있다면 일반적으로 새 운영자 / malloc을 무시하고 할당 블록을 미리 예약해야합니다.
Dunk

3

OO와 같은 접근 방식을 육성하기 위해 불투명 한 데이터 유형을 광범위하게 사용하는 개발 과정에서 나는이 질문에 씨름했습니다. 처음에는 MAGRA "dead code"관점뿐만 아니라 YAGNI 관점에서 소멸자를 제거하는 캠프에 결정적으로 참여했습니다. (나는 충분한 리소스 공간을 가지고 있었지만 고려하지 않았습니다.)

그러나 소멸자가 없으면 자동화 된 단위 / 통합 테스트에서와 같이 테스트가 더 어려워 질 수 있습니다. 일반적으로 각 테스트는 객체를 생성, 조작 및 파기 할 수 있도록 설정 / 분리를 지원해야합니다. 그들은 다음 테스트를 위해 깨끗하고 오염되지 않은 출발점을 보장하기 위해 파괴됩니다. 이를 위해서는 클래스에 소멸자가 필요합니다.

따라서 제 경험에 따르면, YAGNI의 "aint't"는 "are"로 밝혀졌고, 필요하다고 생각하든 없든 모든 클래스에 대해 소멸자를 만들었습니다. 테스트를 건너 뛰더라도 나 뒤에 오는 가난한 슬롭에 대해 올바르게 설계된 소멸자가 적어도 하나 있습니다. (그리고 훨씬 적은 값으로, 코드가 파괴 될 수있는 환경에서 코드를 재사용 할 수있게합니다.)

이 코드는 YAGNI를 다루지 만 데드 코드는 다루지 않습니다. 이를 위해 #define BUILD_FOR_TESTING과 같은 조건부 컴파일 매크로를 사용하면 소멸자를 최종 프로덕션 빌드에서 제거 할 수 있습니다.

이러한 방식으로 수행 : 테스트 / 미래 재사용을위한 소멸자가 있으며 YAGNI의 설계 목표와 "비 사용 코드"규칙을 만족합니다.


테스트 / 제품 코드를 #ifdef '하는 것에주의하십시오. 함수가 실제로 필요한 경우 컴파일이 실패하기 때문에 전체 함수에 적용하면 합리적으로 안전합니다. 그러나 함수 내에서 #ifdef 인라인을 사용하는 것은 이제 prod에서 실행되는 것과 다른 코드 경로를 테스트하기 때문에 훨씬 위험합니다.
케빈

0

당신은 no-op 소멸자를 가질 수 있습니다.

  void noop_destructor(void*) {};

다음의 소멸 설정 Uart아마도 사용하여

  #define Uart_destructor noop_destructor

(필요한 경우 적절한 캐스트 추가)

문서화하는 것을 잊지 마십시오. 어쩌면 당신은 원하는

 #define Uart_destructor abort

또는 소멸자 포인터 함수가 NULL호출을 피하는 것이 일반적인 경우 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.