2013-09-21 2 views
1

여기 내 질문에 의 나는 같은 것을 구성하는 기능을 가지고 말한다. 'e'는 다른 객체에 대한 포인터를 포함합니다. entity의 소멸자가 호출되면 해당 소멸자가 삭제됩니다. 'e'와 엔티티 엔티티 모두 같은 위치를 가리키고 있기 때문에 엔티티에서 포인터로 뭔가를하면 (함수 바깥 쪽) 오류가 발생합니다. 포인터에 있던 것이 무엇이든 함수 반환되었습니다. 이 문제를 해결하는 가장 좋은 방법은 무엇입니까?소멸자 호출 및 포인터

답변

5

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에 도달 할 때만 파괴됩니다.

+0

감사합니다. 내 눈에 아주 잘 설명해. – BWG

+0

중요한 문제에 대한 매우 명확하고 유용한 설명. – john

+0

C++ 11에서는'= delete'이 구현되지 않은 private보다 낫습니다. (그리고 "3의 규칙"은 "5의 규칙"이됩니다). 좋은 스마트 포인터 (unique_ptr/shared_ptr)가 있습니다. – Jarod42

3

shared_ptr을 포함하도록 공유 객체에 대한 포인터를 변경하는 것이 간단한 해결책입니다.

+0

** 모든 포인터 **가 공유 객체에 ** 아마도 변경됩니까? – qdii

+2

그 이유를 이해하지 않고 끝내면 끔찍한 해결책이 될 수도 있습니다. – 6502

+0

흠. 이 작업을 수행하는 방법에 대한 예를 들려 줄 수 있습니까? – BWG

3

이것은 사용자가 rule of three을 위반했기 때문입니다. 소멸자가있는 경우 거의 확실하게 복사 생성자와 할당 연산자가 있어야합니다.

물론 포인터를 다루는 가장 좋은 방법은 포인터를 전혀 사용하지 않는 방법 ("제로의 규칙")을 찾는 것입니다. 컴파일러에서 생성 한 소멸자, 생성자 및 할당 연산자와 같은 상황에서는 자동으로 리소스를 관리 할 수 ​​있습니다.

+0

어떻게 적용할까요? – BWG

+0

@ user2159051 3 개의 규칙을 적용하는 것은 쉽지만 유지 보수에 추가됩니다 : 복사 생성자와 할당 연산자를'entity'에 추가하여 포인터가 가리키는 'e'안에있는 객체가 복사되고 새로운 포인터가 할당되도록하십시오 '엔티티 (entity) '의 사본에. "zero of rule"을 적용하는 것은 더 어렵습니다. 어떤 객체에 대한 포인터를'entity'에 집어 넣는 대신 객체 자체를 넣는 것입니다. 이것은 포인터를 사용하는 것이 더 나은 선택 일 수있는 더 큰 오브젝트보다 작은 오브젝트에 대해 더 잘 작동합니다. – dasblinkenlight

0

엔티티 클래스에 소멸자가있는 경우 rule of three에 의해 복사 및 대입 지정 연산자도 정의해야합니다.

불행히도 이것은 아마도 개체에 지정된 항목을 복사해야하므로 개체 복사본이 나중에 다른 복사본에 의해 삭제 될 항목을 삭제하지 않도록해야한다는 것을 의미합니다. 불행히도 "가리키는 항목의 복제본을 만드는 것이 바람직하지 않기 때문에"; 이 경우에는 디자인에 대한 수수께끼가 있습니다. Tom Kerr의 제안 WRT shared_ptr이 좋은 옵션입니다.

또 다른 해결책은 복사 생성자를 private로 설정하거나 = delete을 사용하여 (C++ 11)을 복사하고 entity에 포인터 배열 (대신 push_back(&e))을 만드는 것입니다.