2015-01-22 2 views
2

이 코드 고려 : 때때로호출 표준 : : 함수 객체

#include <iostream> 
#include <functional> 

using namespace std; 
using namespace std::placeholders; 

typedef function<void(const int&)> SomeFunc; 

class X { 
public: 
    X(string name):name_(name) 
    { cout << "ctor " << name_ << endl; } 

    ~X() 
    { 
     cout << "dtor " << name_ << endl; 
     name_ = "empty"; 
    } 

    SomeFunc 
    getSomeFunc() 
    { return bind(&X::someMethod, this, _1); } 

private: 
    string name_; 

    void 
    someMethod(const int& a) 
    { 
     cout << name_ << " some method with " << a << endl; 
    } 
}; 


int main() 
{ 
    SomeFunc f; 

    { 
     shared_ptr<X> x(new X("Object")); 
     f = x->getSomeFunc(); 
     f(1); 
    } 

    f(2); 

    return 0; 
} 

을, 출력은 저에게이 제공 :

ctor Object 
Object some method with 1 
dtor Object 
empty some method with 2 

다른 시간이 :

ctor Object 
Object some method with 1 
dtor Object 
some method with 2 

현실 세계에서는 할당 취소 된 객체가 속성에 액세스하려고하면 충돌이 발생합니다. 여기에 질문이 있습니다. 함수가 가리키는 대상에 대한 참조를 유지하는 것을 보장하지 않기 때문에 참조 된 개체가 이미 할당 취소 된 후에 함수가 호출 될 때 충돌을 피하는 것이 가장 좋습니다.

내가 생각할 수있는 해결책 중 하나 - 객체 내부에 특수 플래그 bool deallocated_을 유지하고 할당 해제 후 호출 될 수있는 메소드 내부에서 확인하십시오. 그러나, 나는 그것이 신뢰할 수 없다고 생각한다. (주석에서)

업데이트 :

내가이 해결 방법을 필요로하는 진짜 이유를 매개 변수로 기능을 걸리는 라이브러리입니다. 이 라이브러리는 비동기 적으로 작동하며 전달 된 함수 객체를 제어하지 못합니다. 그래서 내 객체가 할당 해제되면 라이브러리는 여전히 충돌로 이어지는 원래 전달 된 함수를 사용하여 콜백을 호출 할 수 있습니다.

+0

귀여운 대답은 "어리석은 짓하지 마라."입니다. – BlamKiwi

+7

음, 매달려있는 포인터를 사용하면 얻는 것을 얻을 수 있습니다. 당신의 진정한 질문은 무엇입니까? 소유권을 더 잘 관리하는 방법을 묻는다면 소유권을 더 잘 관리하는 것이 해결책입니다. –

+1

나는 다른 요일에 이것을 물었다 : http://stackoverflow.com/questions/28054303/stdfunction-to-member-function-of-object-and-lifetime-of-object 아마 도움이 될 것이다. –

답변

1

Sulution 1)b4hand에서 거의 동일한 weak_ptr를 + 람다 (사용 :

#include <iostream> 
#include <functional> 
#include <memory> 

using namespace std; 
using namespace std::placeholders; 

typedef function<void(const int&)> SomeFunc; 

class X : public enable_shared_from_this<X> { 
public: 
    X(string name) : name_(name) { 
     cout << "ctor " << name_ << endl; 
    } 

    ~X() { 
     cout << "dtor " << name_ << endl; 
     name_ = "empty"; 
    } 

    SomeFunc getSomeFunc() { 
     auto ptr = shared_from_this(); 
     return [ptr](const int &a){ ptr->someMethod(a); }; 
    } 

private: 
    string name_; 

    void someMethod(const int& a) { 
     cout << name_ << " some method with " << a << endl; 
    } 
}; 


int main() 
{ 
    SomeFunc f; 

    { 
     shared_ptr<X> x(new X("Object")); 
     f = x->getSomeFunc(); 
     f(1); 
    } 

    f(2); 

    return 0; 
} 

출력은 다음과 같다 :

여기 작품 전체 예제 그러나 당신의 수업 beeing 살아있는 강제하지 않습니다)

표준에서 클래스를 상속 : : 전자

class X : public enable_shared_from_this<X> 

을 nable_shared_from_this이 같은 것으로 getSomeFunc을 변경

SomeFunc getSomeFunc() 
{ 
    weak_ptr<X> weak = shared_from_this(); 

    return [weak, this](const int& a){ 
     shared_ptr<X> shared = weak.lock(); 

     if (shared) 
     { 
      this->someMethod(a); 
     } 
    }; 
} 

출력 :

ctor Object 
Object some method with 1 
dtor Object 

자세한 내용 herehere.

해결 방법 2) 미친 코드 + 람다의 비트
당신이 또는 공유/약한 ptrs을 사용하지 않을 수없는 경우, 당신은이 방법으로 수행 할 수 있습니다

#include <memory> 
#include <functional> 
#include <iostream> 
#include <memory> 
#include <string> 
#include <set> 

using namespace std; 

typedef function<void(const int&)> SomeFunc; 

class X { 
private: 
    static set<X*> _aliveInstanties; 
public: 
    X(string name) :name_(name) 
    { 
     _aliveInstanties.insert(this); 

     cout << "ctor " << name_ << endl; 
    } 

    ~X() 
    { 
     _aliveInstanties.erase(_aliveInstanties.find(this)); 

     cout << "dtor " << name_ << endl; 
     name_ = "empty"; 
    } 

    SomeFunc getSomeFunc() 
    { 
     return [this](const int& a) 
     { 
      if (_aliveInstanties.find(this) != _aliveInstanties.end()) 
      { 
       this->someMethod(a); 
      } 
     }; 
    } 

private: 
    string name_; 

    void someMethod(const int& a) 
    { 
     cout << name_ << " some method with " << a << endl; 
    } 
}; 
+0

감사합니다, @ VinSmile. 솔루션 # 1은 나를 위해 완벽하게 작동합니다. 호출 할 함수에 대한 객체를 보유 할 필요가 없습니다. – peetonn

1

함수 포인터와 객체에 shared_ptr을 포함하는 클래스를 만들 수 있습니다. 객체에 대한 shared_ptr은 함수 클래스가 파괴 될 때까지 객체가 파괴되지 않음을 보장합니다.

auto func = [ptr](const int &p){ ptr->someMethod(p); }; 

당신은 클래스 내에서 ptr를 얻을 수 shared_from_this를 사용해야합니다 : 당신이 shared_ptr을 통해 닫습니다 람다를 사용할 수 있도록

3

개체는 shared_ptr에 의해 개최되고있다. ,

ctor Object 
Object some method with 1 
Object some method with 2 
dtor Object 
+1

이것이 왜 떨어 졌는지 확실하지 않습니다. 클로저는 일반적으로 특정 주의 수명을 충분히 길게하는 도구입니다. – BlamKiwi

+0

Downvote가 삭제되었습니다 - 마지막 편집에서 "dangling reference"버그를 수정했습니다. 너가 알아 차렸을거야. :) –

0

또 다른를 모든 콜백은 REL까지

class X : public enable_shared_from_this<X> { 
public: 
    X(string name):name_(name) 
    { cout << "ctor " << name_ << endl; } 

    ~X() 
    { 
     cout << "dtor " << name_ << endl; 
     name_ = "empty"; 
    } 

    SomeFunc 
    getSomeFunc() 
    { 
     return bind(&X::someMethod, shared_from_this(), _1); 
    } 

private: 
    string name_; 

    void 
    someMethod(const int& a) 
    { 
     cout << name_ << " some method with " << a << endl; 
    } 
}; 

이것은, 그러나, 오브젝트를 보유한다 : 람다를 사용하지 않고 용액 enable_shared_from_this로부터 파생 getSomeFunc 방법 shared_from_this 통과하는 완화되었습니다.