여기 내 질문에 의 나는 같은 것을 구성하는 기능을 가지고 말한다. 'e'는 다른 객체에 대한 포인터를 포함합니다. entity의 소멸자가 호출되면 해당 소멸자가 삭제됩니다. 'e'와 엔티티 엔티티 모두 같은 위치를 가리키고 있기 때문에 엔티티에서 포인터로 뭔가를하면 (함수 바깥 쪽) 오류가 발생합니다. 포인터에 있던 것이 무엇이든 함수 반환되었습니다. 이 문제를 해결하는 가장 좋은 방법은 무엇입니까?소멸자 호출 및 포인터
답변
C++는 "복사 기반"언어이며 예를 들어 Entity
의 컨테이너는 실제로 컨테이너 내부에 사본 사본을 넣습니다.
복사본은 여러 위치에서 C++로 만들어 지므로 클래스가 올바르게 지원하거나 더 이상 사용하지 않는 것이 좋습니다.
클래스에 다른 데이터에 대한 포인터가 있습니다. 클래스의 인스턴스 사본을 만들 때 어떻게해야합니까? 포인터를 복사하는 것이 좋으면, 기존 복사본이 삭제 된 개체를 가리 키기 때문에 소멸자에서 지정된 개체를 삭제해도 괜찮은지 분명히 알 수 있습니다.
이러한 종류의 실수를 피하는 데 도움이되는 간단한 규칙이 있으며 "3 가지 규칙"이라고합니다. 명시 적으로 구분 한 경우 중 하나
- 복사 생성자
- 소멸자
- 할당 한 다음 클래스
는 대부분의 아마 당신이 그 세 가지 모두가 필요합니다 연산자.
이 경우 복사 생성 또는 할당의 경우 수행 할 작업을 알 필요가 있으므로이 경우 소멸자가 기본 오브젝트가 아닙니다 (지정된 오브젝트를 삭제하기 때문에).
당신이 다음 비 복사 가능한 것으로 그 클래스를 선호하는 경우 단지
struct Entity {
Object *o;
Entity(Object *o) : o(o) {
...
}
~Entity() {
delete o;
}
private:
// Taboo... this should just never happen!!!
// Here is a declaration, but no implementation will be written
Entity(const Entity& other); // Copy constructor
Entity& operator=(const Entity&); // Assignment
};
이 그들에게 전화하지 않습니다 해당 사용자 코드를 보장합니다 금지 작업 private
를 선언 할 수 있도록 (이 될 것이다 컴파일 타임 오류) 및 구현을 제공하지 않고 클래스 코드를 선언하는 것만으로도 클래스 코드 자체에서 실수로 호출하지 않도록 할 수 있습니다 (링크 타임 오류가 발생 함).
그러나이 특정 경우에는 Entity
인스턴스를 컨테이너 안에 넣는 것이 금지됩니다 (컨테이너 안의 요소는 복사해야합니다). Entity
포인터를 컨테이너 안에 넣을 수 있습니다 (포인터는 복사 할 수 있으므로 entities
에 대해서는 이 합법입니다)하지만 개체의 올바른 수명을 처리하는 것은 담당 할 것입니다 (누가 소멸자를 호출해야하며 누가 그렇게해야합니까?).
반면에 당신은 클래스 내부의 데이터에 대한 포인터를 가지고 있고 에 당신도 할 수있는 클래스의 인스턴스의 복사본 만들기을 허용하려면 다음
- 복사 또한 뾰족한 데이터 를
- 공유가 다른 인스턴스 뾰족한 데이터 즉, 일반적인 접근 방식 "참조 카운트"포인터를 사용하는 두 번째 솔루션에 대한
사이에 데이터를 지적했다 "인식"얼마나 많은 포인터되어 그것을 참조하고있다 이 카운트가 0에 도달 할 때만 파괴됩니다.
이것은 사용자가 rule of three을 위반했기 때문입니다. 소멸자가있는 경우 거의 확실하게 복사 생성자와 할당 연산자가 있어야합니다.
물론 포인터를 다루는 가장 좋은 방법은 포인터를 전혀 사용하지 않는 방법 ("제로의 규칙")을 찾는 것입니다. 컴파일러에서 생성 한 소멸자, 생성자 및 할당 연산자와 같은 상황에서는 자동으로 리소스를 관리 할 수 있습니다.
어떻게 적용할까요? – BWG
@ user2159051 3 개의 규칙을 적용하는 것은 쉽지만 유지 보수에 추가됩니다 : 복사 생성자와 할당 연산자를'entity'에 추가하여 포인터가 가리키는 'e'안에있는 객체가 복사되고 새로운 포인터가 할당되도록하십시오 '엔티티 (entity) '의 사본에. "zero of rule"을 적용하는 것은 더 어렵습니다. 어떤 객체에 대한 포인터를'entity'에 집어 넣는 대신 객체 자체를 넣는 것입니다. 이것은 포인터를 사용하는 것이 더 나은 선택 일 수있는 더 큰 오브젝트보다 작은 오브젝트에 대해 더 잘 작동합니다. – dasblinkenlight
엔티티 클래스에 소멸자가있는 경우 rule of three에 의해 복사 및 대입 지정 연산자도 정의해야합니다.
불행히도 이것은 아마도 개체에 지정된 항목을 복사해야하므로 개체 복사본이 나중에 다른 복사본에 의해 삭제 될 항목을 삭제하지 않도록해야한다는 것을 의미합니다. 불행히도 "가리키는 항목의 복제본을 만드는 것이 바람직하지 않기 때문에"; 이 경우에는 디자인에 대한 수수께끼가 있습니다. Tom Kerr의 제안 WRT shared_ptr
이 좋은 옵션입니다.
또 다른 해결책은 복사 생성자를 private로 설정하거나 = delete
을 사용하여 (C++ 11)을 복사하고 entity
에 포인터 배열 (대신 push_back(&e)
)을 만드는 것입니다.
- 1. 생성자 및 소멸자 호출
- 2. 소멸자 (this) 포인터 삭제
- 3. 소멸자 호출
- 4. C++에서 소멸자 호출
- 5. 추상 클래스의 소멸자 호출
- 6. 소멸자 및 연결된 목록
- 7. GMock 테스트 소멸자 호출
- 8. C++에서의 소멸자 호출
- 9. 구조체 기본 소멸자 호출?
- 10. C++ 소멸자 및 함수 호출 순서
- 11. 객체 생성과 관련된 생성자 및 소멸자 호출
- 12. 멤버 생성자 및 소멸자 호출 순서
- 13. PostSharp 인터셉트 클래스 생성자 및 소멸자 호출
- 14. 반환 값 레지스터 및 소멸자 호출 순서
- 15. std :: for_each 및 std :: vector 소멸자 호출
- 16. 참조 및 소멸자 ++
- 17. 는 소멸자 스마트 또는 원시 포인터
- 18. 닫기 개체에 대한 소멸자 호출
- 19. derrived 클래스의 소멸자 만 호출
- 20. 소멸자 호출 중에 glDeleteBuffers가 충돌합니다.
- 21. 메서드 내에서 자체 소멸자 호출
- 22. 포인터 및 참조 메서드 호출
- 23. CPP에서 호출 소멸자 메서드를 이해하는 방법?
- 24. 대입 연산자 이전에 호출 된 구조체의 소멸자
- 25. QMainWindow 소멸자
- 26. 네이티브 및 관리되는 소멸자
- 27. 힙 및 클래스 소멸자
- 28. 소멸자 및 noexcept
- 29. 소멸자 및 생성자
- 30. C++ 할당 및 소멸자
감사합니다. 내 눈에 아주 잘 설명해. – BWG
중요한 문제에 대한 매우 명확하고 유용한 설명. – john
C++ 11에서는'= delete'이 구현되지 않은 private보다 낫습니다. (그리고 "3의 규칙"은 "5의 규칙"이됩니다). 좋은 스마트 포인터 (unique_ptr/shared_ptr)가 있습니다. – Jarod42