2013-05-31 2 views
19

허브 셔터는 약 C++ (11)과 동시성C++ 11에서 클래스의 모든 멤버 함수 호출을 래핑하는 방법은 무엇입니까?

여기서 핵심 아이디어는 모든 함수 호출이 잠금 해제 잠금 장식한다 비 잠금 클래스 X을하는 것입니다 (this video 참조) 이야기에서이 질문을 함수 후.

그러나 Herb Sutter는 표류하고 functor 기반 접근 방식을 제공합니다. C++ 11로 각 함수 호출을 잠금 및 클래스 잠금 해제와 함께 일반적인 방법 (모든 함수 호출을 수동으로 래핑하지 않음)으로 래핑하는 것이 가능한지 궁금합니다.

class X { 
    public: 
    X() = default; 
    void somefunc(arg1 x1, arg2 x2, ...); 
    void somefunc2(arg1 x1, arg2 x2, ...); 
    /* and more */ 
}; 

// herb admits one way to make all functions *available* 
// in another class is by derivation 

class XX : public X { 
    public: 
    XX() = default; 
    // all functions available in NON overloaded form... 
}; 

또한 장식 패턴

class XXX { 
    public: 
    XXX(X &x) : m_x(x) {} 

    // explicitly call each wrapped function ... done for each class separately. 
    void somefunc(arg1 x1, arg2 x2, ...); 
    void somefunc2(arg1 x1, arg2 x2, ...); 
    private: 
    class X& m_x; 
}; 

이 있지만 거기에이 가능한 같은 것입니다 :

template<> 
class wrap_everything; 

wrap_everything<X> x; 
x.somefunc(x1,x2,...); // this is then locked. 

완성도를 위해서이 허브 셔터의 펑 기반의 접근 방식은 다음과 같습니다

template <class T> class locker { 
    private: 
    mutable T m_t; 
    mutable std::mutex m_m; 
    public: 
    locker(T t = T{}) : m_t(t) {} 
    template <typename F> 
    auto operator()(F f) const -> decltype(f(m_t)) { 
     std::lock_guard<mutex> _{m_m}; 
     return f(t); 
    } 
}; 


// usage 
locker<std::string> s; 
s([](string &s) { 
    s += "foobar"; 
    s += "barfoo"; 
}); 
+0

일부 컴파일러 (예 : gcc)에서는 컴파일러가 코드를 수정하지 않고도이 작업을 수행 할 수 있습니다. 일반적으로 프로파일 링에 사용되지만 각 함수 호출 전후에 지정된 함수를 호출하도록 할 수 있습니다. 자물쇠를 원하는 위치와 실제로하지 않은 위치를 구분하는 코드는 여전히 중요하지 않습니다. –

+0

@JerryCoffin 코드에서보다 다른 곳에서 잠금을 찾아야하는 것은 모든 관리자가 치명적입니다. – Alex

+0

@Alex 좋은 질문입니다. 나는 Sutter가 2012 년 C++에서 그리고 Beyond 2012에서 그 때를 기억해 냈던 것을 기억하고 있습니다. 어쩌면 그는 C++ 14 기능 세트에 대한 힌트를 포기했을 수도 있습니다. –

답변

15

질문은 EXECUTE-AROUND 패턴에 관한 것입니다.나는 https://gitlab.com/redistd/redistd/blob/master/include/redi/exec_around.h

에서 EXECUTE-AROUND 포인터의 일반 (만 간신히 테스트) 구현을 만들어이 있습니다 :

struct X { void f() { } }; 
auto x = mutex_around<X>(); 
x->f(); // locks a mutex for duration of call to X::f 

의 가족이 될 수 있습니다 주위 패턴 작업을 실행 방법에 대한보다 깊이 explaination

,685 : 관심있는 사람들을위한

+0

나는 그것이 내가 찾고있는 것이 었는지 아직 확신하지 못한다. 그러나 그것은 나를 이미 흥분하게 만든다! – Alex

+0

+1 하하, 맞아! 'operator->'의 연결 동작은! 아주 좋은 해결책. –

6

당신이 원하는 것을 정확히 할 수는 없지만 가까운 것이 가능합니다.

#include <iostream> 

class Foo { 
    public: 
    void one (int x) { 
     std::cout << "Called Foo::one(" << x << ")\n"; 
    } 
    void two (int x, double y) { 
     std::cout << "Called Foo::two(" << x << ", " << y << ")\n"; 
    } 
}; 

class ScopeDecorator { 
    public: 
    ScopeDecorator() { 
     std::cout << "Enter scope\n"; 
    } 
    ~ScopeDecorator() { 
     std::cout << "Exit scope\n"; 
    } 
}; 

template <class Wrappee, class Wrapper> 
class Wrap { 
    public: 
    Wrap (Wrappee& w) : wrappee(w) {} 
    template <typename rettype, typename... argtype> 
     rettype call (rettype (Wrappee::*func)(argtype...), argtype... args) 
     { 
      Wrapper wrapper; 
      return (wrappee.*func)(args...); 
     } 
    private: 
    Wrappee& wrappee; 
}; 

int main() 
{ 
    Foo foo; 
    Wrap<Foo, ScopeDecorator> wfoo(foo); 
    wfoo.call(&Foo::one, 42); 
    wfoo.call(&Foo::two, 32, 3.1415); 
} 
11

현재 C++에서 이것을 수행 할 수있는 일반적인 일반적인 방법이 없다고 생각합니다. 템플리트가 템플릿 매개 변수로 과부하 집합을 취할 수 있다면 (많은 이유로 C++ 14에서 많이보고 싶습니다) 호출 사이트를 x.y(z)에서 x->y(z)으로 변경할 수 있다고 생각합니다. 프록시와 오버로드 된 operator->으로 수행하십시오. 그렇지 않으면, 이런 일을하는 가장 일반적인 방법은 C++ 용 Aspect Oriented Programming 프레임 워크 (예 : AspectC++)를 사용하는 것입니다.

각 구성원 함수 호출을 래핑 할 수 있다는 것은 실제로이 기사의 절반에 불과합니다. Interface Principle에 따르면 클래스의 인터페이스는 클래스를 언급하고 클래스와 함께 제공되는 함수입니다. 여기에는 공용 멤버 함수, 친구 함수 및 클래스와 동일한 네임 스페이스에있는 무료 함수가 포함됩니다. 이러한 함수에 랩핑 된 방식으로 인스턴스를 전달할 수 있다는 것은 Sutter의 접근 방식이 진정한 힘과 유연성을 보여주는 곳에서 멤버 함수 호출을 래핑하는 것보다 훨씬 미묘한 문제입니다.

+3

+1은 AOP를 언급 한 것으로, 이런 종류의 질문에 정확하게 답하는 것을 목표로합니다. –

+7

[클래식 Stroustrup 논문] (http://www.stroustrup.com/wrapper.pdf)에서는 회원 함수 호출을 대괄호로 묶을 수있는 프록시 + 연산자 -> 기술을 설명합니다. –

-1

전적으로 가능하며 Stroustrup 이외의 다른 사람에 의해 오래 전부터 제안되었으며 그의 제안은 여전히 ​​사용 가능합니다. www.stroustrup.com/wrapper.pdf

기본적으로 두 번째 레벨에서 연산자 ->을 재정의하고 첫 번째 연산자 ->에 의해 반환되는 임시 개체의 생성자와 소멸자에서 잠금/잠금 해제 뮤텍스를 사용하는 것이 좋습니다.

두 번째 연산자 ->은 메서드가 호출 될 객체의 포인터를 반환합니다.

관련 문제