指向成员指针的功能:安全和替代方案

时间:2014-09-12 19:19:42

标签: c++ c++11 member-function-pointers

在这个问题中,假设我们已经以一种漂亮,谨慎的方式处理了所有指针 - 为了防止问题膨胀,我不想在这里包含我的清理代码!

假设我们有两个类FooBar,其类定义如下:

class Foo
{
    public:
        Foo();
        void fooFn();
};

class Bar
{
    public:
        Bar();
        void barFn();
};

假设FooBar有必要没有继承关系,但我们需要调用fooFnbarFn来响应某些刺激。我们可以创建一个带有容器的控制器类,可以在fooFnbarFn的特定实例上调用FooBar - 例如静态std::vector - 但是我们遇到了一个问题:指向FooBar实例的成员函数的指针属于不同的类型。

通过在控制器类中使用静态vector< std::function<void()>* >,我们可以进行解决方法。 FooBar个实例可以有一个函数,通过一个捕获this的lambda函数为向量添加指针:

void Foo::registerFnPointer()
{
    ControllerClass::function_vector.push_back( new [this](){ return this->fooFn(); } );
}

我已经测试了这种方法,它似乎没有任何问题。也就是说,我担心可以通过规避之前提到的类型差异引起的问题......我是否担心什么?有没有更好的方法来实现同等功能?

2 个答案:

答案 0 :(得分:1)

我看到的唯一问题实际上与仿函数无关,而是与对象生命周期有关。那就是:我不确定你是如何确保每当Foo或Bar实例被销毁时你总是取消注册用ControllerClass注册的仿函数。

但是,你提到你做了适当的内存管理。

在我看来,您不需要存储指向function<void()>的指针,您只需将函数存储为值(即vector<function<void()>>)。

在C ++ 11和lambdas之前,为了达到相同的效果你也会使用(boost)函数,但是你会使用boost :: bind和fooFn的地址以及绑定到的第一个参数指向Foo对象实例的指针(或引用)。

这将创建一个函数实例,该实例包含在给定对象上调用fooFn方法所需的所有信息。然后,您可以将实例存储在向量中以便稍后调用它(并且确保没有绑定到已销毁对象的boost::function仍然注册的问题同样存在)

编辑:

为了完整起见,指向绑定成员的Boost绑定文档的链接:http://www.boost.org/doc/libs/1_56_0/libs/bind/bind.html#with_member_pointers

你正在做的事情实际上非常相似,只是你现在使用lambda捕获对象指针并定义要调用的函数。

所以我认为你正在做的事情没有问题(除了我已经提到的那个)。

答案 1 :(得分:-1)

您可以使用适配器类。对于你正在做的事情,这可能有点过头了,但它可能有效。

这样做的好处是:

  1. 您不必更改原始课程。创建void Foo::registerFnPointer()很难看。

  2. 您不必使用静态std::vector

  3. 您不必处理函数指针。

  4. 所以,让我们说你有两个不同的类:

    struct Foo
    {
        void fooFn () { 
            std::cout << "Foo::fooFn ()" "\n" ; 
        }
    };
    
    struct Bar
    {
        void barFn () {
            std::cout << "Bar::barFn ()" "\n" ; 
        }
    };
    

    目标是将它们放入容器并调用各自的*Fn ()成员函数。

    适配器看起来像这样:

    struct Adapter_Base
    {
        virtual ~Adapter_Base () {} ;
    
        virtual void adapterFn () = 0 ;
    };
    
    template <typename T>
    struct Adapter : Adapter_Base
    {
        T tVal ;
    
        Adapter (const T &tVal) : tVal (tVal) {}
        void adapterFn () ;
    };
    
    template <>
    void Adapter <Foo>::adapterFn ()
    {
        tVal.fooFn () ;
    }
    
    template <>
    void Adapter <Bar>::adapterFn ()
    {
        tVal.barFn () ;
    }
    

    你可以像这样使用它:

    int main ()
    {
        std::vector <std::unique_ptr <Adapter_Base> > v1 ;
    
        std::unique_ptr <Adapter_Base> u1 (new Adapter <Foo> (Foo ())) ;
        std::unique_ptr <Adapter_Base> u2 (new Adapter <Bar> (Bar ())) ;
    
        v1.push_back (std::move (u1)) ;
        v1.push_back (std::move (u2)) ;
    
        for (auto &adapter : v1) {
            adapter->adapterFn () ;
        }
    
        return 0 ;
    }