2012-03-26 5 views
4

질문에 대한 답변 : boost::shared_ptr 여기에부스트 :: shared_ptr의 적절한 사용?

나는 3 개의 클래스가 있습니다.

A은 모든 것을 관리하는 일종의 메인 클래스입니다.

B은 약간의 작업을 수행하는 기능을 가진 클래스입니다.

Dispatcher은이 스레드에서 수행 된 Instites of B에서 작업을 가져 오는 별도의 스레드를 감싸는 클래스입니다.

따라서 다음과 같이 작동합니다. A의 인스턴스는 Dispatcher입니다. 이제는 A 인스턴스가 B의 인스턴스를 생성하고 디스패처로 전달합니다.

중요한 부분은 B이 완료되면 A::callback()으로 전화해야한다는 것입니다. B 그것의 생성자에 대한 참조를 가져옵니다 이유는

A.hpp

class A : public boost::enable_shared_from_this<A> 
{ 
public: 
    A(); 
    void sendB(); 
    void callback(); 
private: 
    Dispatcher m_Dispatcher; 
}; 

B.hpp

class B 
{ 
public: 
    B(boost::shared_ptr<A> ptr); 
    boost::shared_ptr<A> m_PointerToA; 
/* Some other functions */ 
}; 

Dispatcher.hpp

class Dispatcher 
{ 
public: 
    void run(); 
    void dispatch(boost::shared_ptr<B> b); 
private: 
    void doWork(); 
    boost::thread m_Thread; 
}; 
(아래 코드 참조)

A.cpp

A::A() 
{ 
    m_Dispatcher.run(); 
} 
void A::sendB() 
{ 
    boost::shared_ptr ptr_B; 
    ptr_B.reset(new B(this->shared_from_this); 
    m_Dispatcher.dispatch(ptr_B); 
} 

B.cpp

B::B(boost::shared_ptr<A> ptr) : 
    : m_PointerToA(ptr) 
{ 
} 

main_example.cpp

int main() 
{ 
    A instanceA; 
    while(true) 
    { 
      instanceA.sendB(); 
      /* Do some other stuff */ 
    } 
    return 0; 
} 

그래서 내 질문은 :

는이 목적을 위해 부스트 :: shared_ptr을 사용하기 적당한가요?

shared_ptr이 여기에 적합한 것인지 확실하지 않습니다. 내 문제는, 내가 정확히 B에서 생성자를 호출하고 this 포인터를 전달하면 어떻게되는지 모르겠다. 이제 shared_ptr에 따르면 은 A의 소유권을 취한다고 가정합니다. 그러나 이것은 Dispatcher의 작업이 완료되고 B의 인스턴스가 삭제되면 m_PointerToA에 대한 참조도 삭제된다는 것을 의미합니다. 실제로는 A이라는 실제 인스턴스가 메인에도 있지만 실제로 개체 자체를 죽일 수도 있습니다. 고리.

업데이트 :

추가 된 몇 가지 코드와 업데이트 된 질문 자체가 좀 더 명확하게하기.

+0

스레드 경계를 넘어서서 'shared_ptr'을 사용하고 싶지는 않습니다. 이것은'std :: auto_ptr'의 의미가 실제로 빛나는 곳입니다; 포인터를 다른 스레드에 전달한 후에는 원래 스레드에서 포인터에 액세스 할 수 없습니다. –

+0

'boost :: shared_ptr'는 안전 상태에 있도록 참조 카운팅에 의존 할 수 있다는 점에서 실제로는 스레드 안전합니다. – Ylisar

+0

@JamesKanze하지만 내가 지나가는 포인터는 실제로'this' 포인터입니다. 그래서 실제로 저는 특히 "포인터"에 대해 아무 것도하지 않습니다. 그러나 물론 'this'의 인스턴스에있는 일부 코드는 여전히 메인 스레드에서 실행 중입니다. 실제로'shared_ptr'을 사용하기를 원했기 때문에 참조를 잃어 버려서 문제가 생기지 않았습니다. 난 또한 원시 포인터를 사용하여 아무 문제가 없을 것이다 ... – Toby

답변

1

예, shared_ptr 만 복사하거나 할당해도 괜찮습니다. 참조 횟수가 늘어납니다. this (참조 카운트 1) 할당 할 때, 그래서/참조 카운트는 2 일시적으로 증가, m_PointerToA 복사-구성에 의해 개최되는 weak_ptr에서 (일시적 여기) shared_ptr 당신의 예에서

, shared_from_this()가 생성됩니다 ctor가 반환되기 전에 임시 객체가 삭제되고 참조 카운트가 다시 1로 감소합니다 (shared_ptr이 B 객체의 한 인스턴스를 "인식"함).

그렇다면 B가 삭제되면이 경우 A가 삭제됩니다 (참조 횟수가 0으로 떨어짐).

B의 내 인스턴스가 삭제 된 경우는 의미

귀하의 관심, 그것은 또한 또한 내 인스턴스를 죽일 m_PointerToA을 삭제합니다. 물론 A의 원래 인스턴스는 다른 곳에서 개최됩니다.

는 당신이/필요성을 계획하는 경우/추가 사용에 대한 A의 인스턴스에 대한 포인터를 유지하려는 것을 보여줍니다, 당신은 shared_ptr뿐만 아니라 원시 포인터 그렇게해야한다. 당신이 A의 인터페이스의 컨트롤이있는 경우, 가장 쉬운 방법은이 같은 named constructor 다음과 같습니다

class A : public boost::enable_shared_from_this<A> { 
    public: 
     static boost::shared_ptr<A> create(); 

     void initClassB(); 
     // .... 
    private: 
     A(); 
     A(const A & other); 
     A& operator=(const A & rhs); 

}; 

boost::shared_ptr<A> A::create() { 
    return boost::shared_ptr<A>(new A()); 
} 

그런 B의 인스턴스가 삭제되는 경우에도, A의 인스턴스가 여전히 살아남을 것의 참조 카운트 때문에 shared_ptr은 여전히 ​​(적어도) 1입니다.

+0

좋아요. 왜 당신의 솔루션이 참조 횟수가 적어도 1이 될 것이기 때문에 A가 삭제되지 않을 것이라고 확신합니다. 그러나 누군가가 (예를 들어, 주요 함수 나 다른 클래스) 호출 할 필요가 있습니다. 'A :: create()'메쏘드 - 그래서 당신의 솔루션을 사용하는 대신이 메인 함수가 AI의 일반적인 인스턴스를 만들면'B'가 삭제되는 동안 그것을 잃을 수 있습니까? 그래서 A는 그 객체의 실제 인스턴스가 있다는 사실에도 불구하고 삭제 될 것입니까? – Toby

+0

"해당 개체의 실제 인스턴스가 있음에도 불구하고"당신이 의미하는 바가 확실하지 않습니다. 'shared_ptr'는 참조가 0으로 떨어지면 인스턴스를 파괴 할 것입니다.'B'에'A'에'shared_ptr'가 하나 밖에 없다면, B를 파괴하면 A의 인스턴스가 파괴 될 것입니다. 원시 포인터를 통해 어딘가에있는 A를 참조하는 경우이를 방지 할 방법이 없습니다. 그렇기 때문에 스마트 포인터를 일관되게 사용해야합니다 (스마트 포인터로 관리되는 개체에 원시 포인터를 사용하지 마십시오). –

+0

위의 예제에서 main 함수는 사용 가능한/액세스 가능한 생성자가 없기 때문에 (A 시도) 컴파일러에서 오류를보고하는 "A"의 "정상"인스턴스 (원시 포인터)를 만들 수 없습니다. 'A'의 인스턴스를 만드는 유일한 방법은'A :: create()'를 호출하는 것입니다. –

4

이 디자인에는 특별한 문제가 없습니다.그러나 대신 boost::function<> & boost::bind을 사용하는 것이 좋습니다. 그것은 당신에게 콜백을위한 더 나은 유연성을 제공하고 B를 A와 단단히 묶지 않습니다. 물론 당신은 여전히 ​​일반적인 스레딩주의 사항의 다양성을 가져야합니다.

+0

+1. 좋은 조언. 또한 인스턴스의 수명을 완벽하게 제어 할 수 있다면 간단히 * 참조 *를 A에 저장할 수 있습니다. 'B'가 물론 지정할 필요가 없다면. – ereOn

+0

그래, 좀 더 일반적인 일을 생각했는데, 첫 시도에서 나는 단지 그것을 원했어. 그래서 boost :: shared_ptr을 사용하면 실제로 문제가 없습니까? – Toby