2010-12-10 5 views
4

boost :: shared_ptr는 정말 저를 괴롭 힙니다. 확실히, 나는 그러한 일의 유용성을 이해하지만 나는 shared_ptr<A>으로 A*으로 사용할 수 있기를 바란다. 다음 코드를 고려하십시오.C++ : 객체에 대한 공유 포인터가 아닌 공유 객체 만들기

class A 
{ 
public: 
    A() {} 
    A(int x) {mX = x;} 
    virtual void setX(int x) {mX = x;} 
    virtual int getX() const {return mX;} 
private: 
    int mX; 
}; 


class HelpfulContainer 
{ 
public: 
    //Don't worry, I'll manager the memory from here. 
    void eventHorizon(A*& a) 
    { 
     cout << "It's too late to save it now!" << endl; 
     delete a; 
     a = NULL; 
    } 
}; 


int main() 
{ 
    HelpfulContainer helpfulContainer; 

    A* a1 = new A(1); 
    A* a2 = new A(*a1); 
    cout << "*a1 = " << *a1 << endl; 
    cout << "*a2 = " << *a2 << endl; 
    a2->setX(2); 
    cout << "*a1 = " << *a1 << endl; 
    cout << "*a2 = " << *a2 << endl; 
    cout << "Demonstrated here a2 is not connected to a1." << endl; 

    //hey, I wonder what this event horizon function is. 
    helpfulContainer.eventHorizon(a1); 

    cout << "*a1 = " << *a1 << endl;//Bad things happen when running this line. 
} 

HelpfulContainer를 만든 사람은 누구나 A 개체에 대한 포인터를 보유하려고한다고 생각하지 않았습니다. 우리는 HelpfulClass boost :: shared_ptr 객체를 줄 수는 없습니다.

class SharedA : public A 
{ 
public: 
    SharedA(A* a) : mImpl(a){} 
    virtual void setX(int x) {mImpl->setX(x);} 
    virtual int getX() const {return mImpl->getX();} 
private: 
    boost::shared_ptr<A> mImpl; 
}; 

그리고 주요 기능은 같은 것을 볼 수 있습니다 :하지만 우리가 할 수있는 한 가지는 A 인 자체 SharedA를 만들 pimlp 관용구를 사용하고, 그래서

int main() 
{ 
    HelpfulContainer helpfulContainer; 

    A* sa1 = new SharedA(new A(1)); 
    A* sa2 = new SharedA(sa1); 
    cout << "*sa1 = " << *sa1 << endl; 
    cout << "*sa2 = " << *sa2 << endl; 
    sa2->setX(2); 
    cout << "*sa1 = " << *sa1 << endl; 
    cout << "*sa2 = " << *sa2 << endl; 
    cout << "this demonstrates that sa2 is a shared version of sa1" << endl; 

    helpfulContainer.eventHorizon(sa1); 
    sa2->setX(3); 
    //cout << "*sa1 = " << *sa1 << endl;//Bad things would happen here 
    cout << "*sa2 = " << *sa2 << endl; 
    //but this line indicates that the originally created A is still safe and intact. 
    //only when we call sa2 goes out of scope will the A be deleted. 
} 

을 내 질문은 이것이다 : 위 패턴은 좋은 패턴인가, 아니면 내가 아직 고려하지 않은 것이있다. 내 현재 프로젝트는 내가 필요로하는 포인터를 삭제하는 위의 HelpfulContainer 클래스를 상속 받았지만 여전히 HelpfulContainer에있는 데이터 구조가 필요합니다.


업데이트 :이 question은 후속 질문입니다.

+0

HelpfulContainer가 포인터의 소유권을 가져 오려면 올바른 의미 체계를 사용해야합니다. 'eventHorizon' 인터페이스는 어떤 일이 일어나고 있는지 설명하지 않고, 소유권이 이전되고 있음을 나타내야합니다 (std :: auto_ptr 또는 새로운 대체 std :: unique_ptr). 이 두 가지 모두 HelpfullContainer 객체가 객체의 소유권을 가져오고 있으므로 호출 후에 더 이상 유효하지 않음을 나타냅니다. 그래서 당신은 C++ 코드가 언어의 의미를 이해하지 못하는 사람들에 의해 심하게 쓰여질 수 있다는 점을 증명합니다. –

답변

6

shared_ptr의 요점은 그것이 (및 사본) 그것이 가리키는 객체를 소유하고 있습니다. 평생을 관리하는 컨테이너에 A을주고 싶다면 shared_ptr을 사용하지 않아야합니다. HelpfulContainer은 동적으로 생성 된 개체의 유일한 소유자가되는 방법 만 알고 있으므로 다른 개체가 소유하지 않은 개체에 대한 포인터를 제공해야합니다.

보통은 인 것으로 생각합니다. 자신의 일생을 돌봐주는 객체 (예외가 있음)에 대한 디자인이 좋지 않습니다. 일반적으로 객체가 작업을 수행 할 수 있고 가능한 다른 일이 가능한 가장 간단한 수명 전략 (예 : 지역/자동 변수)을 선택하여 생성 및 설명을 관리하는 경우에 유용합니다.

협력하지 않는 두 가지 (예 : shared_ptrHelpfulContainer)간에 소유권을 절대적으로 공유해야하는 경우 일종의 프록시 기술을 사용해야합니다.

그러나이 경우에는 HelpfulContainer처럼 보이지는 않습니다.

+1

+1 : 그저 저주받은 컨테이너를 바꾸고 (그것을 사용하여 코드를 신중하게 검토하십시오), 예를 들어'shared_ptr '을 사용하여 과부하를 추가하는 것이 유용 할 수 있습니다. –

0

그러면 삭제가 괜찮은 대치 (SharedA)가 생성됩니다. 비록 다소 어색하지만, 기존 API로 작업하는 것이 필요합니다. 약간이 개선하려면 다음 shared_ptr의에서 SharedA의 건설을 허용하지만 다른 주위 방법 - 당신이 절대적으로해야 할 때 다음에만 SharedP를 사용

int main() 
{ 
    HelpfulContainer helpfulContainer; 

    boost::shared_ptr<A> sa1(new A(1)); 

    // deletes its parameter, but that's okay 
    helpfulContainer.eventHorizon(new SharedA(sa1)); 
} 
1

나는 이것이 당신을 위해 무엇을하는지 모르겠습니다.

helpfulContainer.eventHorizon() 항상이 매개 변수를 삭제 경우, 왜 단지 (원본) 클래스의 새 복사본 통과하지 : helpfulContainer.eventHorizon()은 때때로 후 제작, 자사의 매개 변수를 삭제하면,

helpfulContainer.eventHorizon(new A(sa1)); 

또는를

helpfulContainer.eventHorizon(new SharedA(sa1)); 

로 호출 모두에게 SharedA 원래을 (S 누출 a1) 삭제하지 않기로 선택한 경우.

+0

eventHorizon이 포인터를 삭제하지 않고 데이터 구조에 저장하는 경우가 있습니다. 연관된 shared_ptrs가 모두 삭제되면 데이터 구조에 숨겨진 잘못된 포인터가 있습니다. – JnBrymn

+0

eventHorizon이 포인터의 소유권을 가져다가 결국 삭제할 것이라는 것을 알고 있고 소유권을 유지해야하는 경우 - 내가 보여준 첫 번째 양식과 같이 새 사본을 전달하십시오 ('helpfulContainer.eventHorizon (새 A (sa1));). –

+0

@ John Berryman : 아마도 귀하의 의견을 잘못 해석했습니다. 첫 번째 문장으로 : eventHorizon이 포인터를 보유하고 여유 시간에 삭제하면 동일한 객체에 계속 액세스해야하므로 제안 **이 도움이 될 수 있습니다. 그러나 원시 A' 객체에 대한 포인터가'SharedA' 객체를 통하는 경우를 제외하고 결코 사용되지 않도록 코드를 매우 철저히 리팩토링해야합니다. 두 가지를 섞으려는 시도는 많은 울음 소리와 치아를 .아 먹을 것입니다. 나는 당신이 또한'mImpl'을 복사하는 SharedA (const SharedA &)를위한 특별한 복사 생성자를 원할 것이라고 생각한다. –

0

기본 포인터 유형에 대한 암시 적 변환은 shared_ptr의 의도 된 사용과 일치하지 않으므로 실현하지 않고 shared_ptr을 함수 등으로 쉽게 전달할 수 있습니다.

HelpfulContainer은 도움이되며 고정되거나 버려야합니다.

그럴 수 없다면 가장 좋은 방법은 전달하고자하는 A을 복사하여 컨테이너에 전달하는 것입니다.

관련 문제