2014-07-14 15 views
0

나는 클래스 bar의 방법 중 하나에 멤버 함수 포인터를 받아 클래스 foo을 가지고 있지만 foo이 펑터 이전 bar의 존재를 확인 할 수있는 방법이보다 클래스 바는 짧은 수명을 가질 수있다 실행 중입니까?검증 펑터의 대상 개체

현재 std::functionbool operator을 사용하려고합니다.

class Foo 
{ 
public: 
    void Foo::SetCallback(std::function< void(void) > cb) 
    { 
     _cb = cb; // My Bar class will call this to assign a Bar member function pointer to Foo's _cb member variable 
    } 
    void Foo::CallCallback() 
    { 
     if(_cb) _cb(); // This evaluates to true even if the original bar object has been destroyed 
     //I want this callback to only execute if the bar object exists 
    } 
private: 
    std::function< void(void) > _cb; 
}; 
class Bar 
{ 
public: 
    Bar(Foo* _foo) 
    { 
     _foo->SetCallback(std::bind(&myCalledbackFunc, this); 
    } 
    void myCalledbackFunc() 
    { 
     //do stuff 
    } 
}; 
+0

죄송합니다. 귀하의 질문에 완전히 불명확합니다. 'bar'는 정확히 무엇입니까? 실제로 발생하는 동작과 오류를 재현하는 [최소 샘플] (http://stackoverflow.com/help/mcve)을 입력하십시오. –

+1

function 매개 변수로 functor 외에도 bar 인스턴스의 weak_ptr을 갖는 것은 어떻습니까? – Silvester

+0

@SilvesterSeredi는 좋은 생각처럼 들리지만 ... 저는'std :: weak_ptr'에 익숙하지 않습니다. 단순히'bar' ctor에서'this'에서 만들 수 있습니까? –

답변

0

은 객체의 파괴에 제로되지 않습니다. 따라서 Silvester Seredi은 그의 답변에서 참조하는 객체가 파괴되었는지 여부를 알 수있는 유일한 방법은 포인터가 자동 포인터 소유 객체를 참조하는 것입니다. 또한 오브젝트가 내부적으로 소유 될 수 없으므로 오브젝트가 본질적으로 오브젝트가 손상되었는지에 대한 표시기를 제공 할 수 없습니다.

따라서 유일한 해결책은 functor를 가지고있는 클래스에, perreal에서 제안한 것처럼, functor가 멤버를 참조하는 클래스가 파기되었을 때 유효하지 않음을 알리는 것입니다. 이것은 다중 스레드에 안전하지 않습니다.

class Foo 
{ 
public: 
    void SetCallback(std::function< void(void) > cb) 
    { 
     _cb = cb; 
    } 
    void UnSetCallback() 
    { 
     _cb = std::function< void(void) >(); 
    } 
    void CallCallback() 
    { 
     if(_cb) _cb(); 
    } 
private: 
    std::function< void(void) > _cb; 
}; 
class Bar 
{ 
public: 
    Bar(Foo* foo) : _foo(foo) 
    { 
     _foo->SetCallback(std::bind(&myCalledbackFunc, this); 
    } 
    ~Bar() 
    { 
     _foo->UnSetCallback(); 
    } 
    void myCalledbackFunc() 
    { 
     //do stuff 
    } 
private: 
    Foo _foo; 
}; 
1
내가 콜백 객체가 소멸 될 때 푸 알려하는 방법 어떤 간단한 방법을 생각할 수 없다,하지만 당신이 정말로 개체가 살아 있는지 여부를 푸 클래스에서 확인하고 싶은 경우, 나는를 사용하십시오

약한 곳은 길을 따라 어딘가에 있습니다.

class Bar; 
class Foo 
{ 
public: 
    void Foo::SetCallback(std::function< void(void) > cb) 
    { 
     _cb = cb; 
    } 

    void Foo::RegisterBar(std::weak_ptr<Bar> inbarPtr) 
    { 
     barRef = inbarPtr; 
    } 

    void Foo::CallCallback() 
    { 
     if(_cb && !barRef.expired()) _cb(); 
    } 

private: 
    std::function< void(void) > _cb; 
    std::weak_ptr<Bar> barRef; 
}; 

class Bar 
{ 
public: 
    Bar(Foo* _foo) 
    { 
     _foo->SetCallback(std::bind(&Bar::myCalledbackFunc, this)); 
    } 
    void myCalledbackFunc() 
    { 
     //do stuff 
    } 
}; 

int main() 
{ 
    Foo fooInstace; 
    std::shared_ptr<Bar> barInstance = std::make_shared<Bar>(&fooInstace); 
    fooInstace.RegisterBar(barInstance); 
    return 0; 
} 

당신이 만약 정말로 : 당신이 new을 통해 줄을 만드는 경우 대신 make_shared를 통해 인스턴스를 만들 수 있습니다 당신은 같은 것을 할 것 (추가 비용은 바 인스턴스의 모든 건설 후 하나의 함수 호출) 단지 바 클래스에 대한 변경 사항에, 당신은 빈 사용자 정의 Deleter가와 못생긴, 추한 해킹을 사용할 수 있습니다 주장 해 :

객체에서 사용하는 메모리 ++ C에서
class Bar; 
class Foo 
{ 
public: 
    void Foo::SetCallback(std::function< void(void) > cb , std::weak_ptr<Bar> inbarPtr) 
    { 
    _cb = cb; 
    barRef = inbarPtr; 
    } 
    void Foo::CallCallback() 
    { 
    if(_cb && !barRef.expired()) _cb(); 
    } 
private: 
    std::function< void(void) > _cb; 
    std::weak_ptr<Bar> barRef; 
}; 


class Bar 
{ 
    std::shared_ptr<Bar> selfPtr; 
public: 
    Bar(Foo* _foo) 
    { 
    selfPtr = std::shared_ptr<Bar>(this, Bar::EmptyDeleter); 
    _foo->SetCallback(std::bind(&Bar::myCalledbackFunc, this), selfPtr); 
    } 
    void myCalledbackFunc() 
    { 
    //do stuff 
    } 
protected: 
    static void EmptyDeleter(Bar*) 
    { 
    } 
}; 
+0

그래서 내 코드에서,'Bar' 예제 클래스는 템플릿 팩토리에 의해 생성되고 factory는'std :: unique_ptr'을 사용하여 멈춰서 그것을 정리할 책임이 있습니다. 공장 코드는 나머지 설계에서 의미하는 바가 있기 때문에 변경할 수 없습니다. 'Bar' 클래스의 코드 *를 사용하여 솔루션을 끌 수있는 방법이 있습니까? –

+0

unique_ptr을 shared_ptr로 변경할 수 없습니까? 변경 사항은 간단해야합니다 – Silvester

+0

꽤 중요한 변화처럼 보이는 코드를 보면 ... 내가 그것을 만들 수 있다고 가정 해 봅시다 ... 저는 여전히 공장이 보유하고있는'std :: shared_ptr'을 얻을 수 없습니다. 'Bar' 클래스의 'Bar' 오브젝트입니다. 그래서 전환은 실제로 나에게 아무것도 사지 않는다고 생각합니다. –