문제

물체를 캡슐화하고 수명을 관리하는 가장 좋은 방법은 무엇입니까? 예 : 수업이 있습니다 , 그것은 유형의 객체를 포함합니다 그리고입니다 전적으로 책임이 있습니다 그것을 위해.

해결책 1, 클론 이를 확인하기 위해 개체 그것을 청소할 수 있습니다.

class A
{
    B *b;
public:
    A(B &b)
    {
        this->b = b.clone();
    }

    ~A()
    {
        delete b; // safe
    }
};

해결책 2, 전달 된 물체를 직접 사용하면 여기서는 이중 자유가 발생할 위험이 있습니다.

class A
{
    B *b;
public:
    A(B *b)
    {
        this->b = b;
    }

    ~A()
    {
        delete b; // unsafe
    }
};

실제 경우 솔루션 #2가 가장 잘 맞습니다. 그러나 누군가가 행동에 대해 모를 수도 있기 때문에 이것이 나쁜 코드로 간주되는지 궁금합니다. , 문서화 된 경우에도. 이 시나리오를 생각할 수 있습니다.

B *myB = new B();
A *myA = new A(myB);
delete myB; // myA contains a wild pointer now

또는,

B *myB = new B();
A *firstA = new A(myB);
A *secondA = new A(myB); // bug! double assignment
delete firstA; // deletes myB, secondA contains a wild pointer now
delete secondA; // deletes myB again, double free

A의 동작을 올바르게 문서화하면 이러한 문제를 무시할 수 있습니까? 책임을 선포하고 문서를 읽기 위해 다른 사람들에게 맡기는 것으로 충분합니까? 코드베이스에서 어떻게 관리됩니까?

도움이 되었습니까?

해결책

소유권 시맨틱이 가능한 한 많이 인터페이스에 의해 정의되도록 객체를 정의해야합니다. David Thornley가 지적했듯이 std :: auto_ptr은 선택한 스마트 포인터입니다. 소유권 양도. 수업을 그렇게 정의하십시오.

class A
{    
    std::auto_ptr<B> b;
public:    
    A(std::auto_ptr<B> b)    
    {
        this->b = b;
    }
    // Don't need to define this for this scenario
    //~A()
    //{ 
    //   delete b; // safe
    //}
};

std :: auto_ptr의 계약은 과제 = 소유권의 전송이기 때문에, 당신의 생성자는 이제 A 객체가 통과 된 포인터의 소유권을 가지고 있음을 암시 적으로 말합니다. 실제로, 클라이언트 인 경우 시도합니다 u003CB>구조 후 A를 건설하는 데 사용한 std :: auto_ptr로 무언가를하기 위해, 보유한 포인터가 유효하지 않기 때문에 작업이 실패합니다.u003C/b>

다른 팁

내가 정말로 필요하지 않으면 아무것도 삭제하지 않습니다. 그것은 오류로 이어집니다.

똑똑한 포인터는 당신의 친구입니다. std::auto_ptr<> 한 객체가 다른 객체를 소유하고 범위를 벗어날 때 삭제할 책임이있는 친구입니다. boost::shared_ptr<> (또는 지금, std::tr1::shared_ptr<>) 다른 객체에 첨부 된 객체가 하나 이상있을 때 친구이며, 더 이상 참조가 없을 때 객체를 삭제하려고합니다.

따라서 솔루션 1을 사용하십시오 auto_ptr, 또는 솔루션 2와 함께 shared_ptr.

다른 사람이 나중에 사용할 코드를 작성하는 경우 이러한 문제를 해결해야합니다. 이 경우 간단한 참조 계산 (아마도 스마트 포인터)을 사용합니다. 다음 예를 고려하십시오.

캡슐화 클래스의 인스턴스에 객체 B가 할당되면 객체의 B 참조 카운터를 증가시키는 메소드를 호출합니다. 캡슐화 클래스가 파괴되면 B를 삭제하지 않지만 대신 메소드가 참조 수가 줄어 듭니다. 카운터가 0에 도달하면 객체 B가 파괴됩니다 (또는 그 문제에 대해 스스로 파괴). 이런 식으로 클래스 캡슐화의 여러 인스턴스는 단일 인스턴스의 객체 B에서 작동 할 수 있습니다.

주제에 대한 자세한 내용 : 참조 계산.

객체가 전달 된 물체에 대한 책임이있는 경우 삭제하는 것은 안전해야합니다. 당신이 전적으로 책임이 있다는 주장보다 안전하지 않은 경우 거짓입니다. 그래서 그것은 무엇입니까? 인터페이스가 인바운드 객체를 삭제할 것을 문서화 한 경우, 귀하가 삭제 해야하는 객체를받는 것이 발신자의 책임입니다.

A를 복제하고 A1과 A2가 모두 B에 대한 참조를 유지하는 경우 B의 수명은 전적으로 A A에 의해 제어되지 않습니다. 다양한 A 중 공유되고 있습니다. B는 AS와 BS 간의 일대일 관계를 보장합니다. 평생 일관성을 보장하기가 쉽습니다.

B 클로닝 B가 옵션이 아닌 경우 A는 B의 수명에 책임이 있다는 개념을 폐기해야합니다. 다른 객체는 다양한 B를 관리해야하거나 참조 계산과 같은 메소드를 구현해야합니다.

참고로, '클론'이라는 용어를 생각할 때, 그것은 딥 카피를 암시하며, 이는 B를 복제 할 것입니다. 나는 클론 후 두 사람이 서로 완전히 분리 될 것으로 기대한다.

나는 불필요하게 물건을 복제하거나 "안전하기 위해"복제하지 않습니다.

대신 나는 문서를 통해 또는 스마트 포인터를 통해 무언가를 삭제하는 것이 어떤 책임이 있는지 알고 있습니다. create 기능을 인스턴스화하고 포인터를 반환하고 삭제하지 않으면 삭제해야 할 곳과 어디에 삭제 해야하는지 불분명 한 기능 create벌거 벗은 포인터를 반환하는 것은 내가 정의 할 수 있습니다 create스마트 포인터에 포함 된 포인터를 반환하는 반환 유형.

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