如何编写一个可以接受函数指针和/或仿函数的类,就像智能​​指针一样,可以用于自定义删除器?

时间:2013-12-09 19:47:48

标签: c++ boost function-pointers functor tr1

我正在尝试编写一个接受函数指针和/或函数的类,以便稍后由该类使用。 为了更好地说明我想做的事情:

template <typename T> class Holder {
private:
  T *m_ptr;
  <something> m_func;

public:
  Holder(T *ptr) : m_ptr(ptr), m_func(NULL) {
  }

  Holder(T *ptr, <something> func) : m_ptr(ptr), m_func(func) {
  }

  ~Holder() {
    if (m_func) {
      m_func(m_ptr);
    } else {
      delete m_ptr;
    }
  }
};

考虑到我想处理这种类型的对象:

class MyClass {
public:
  void describe() {
    cout << "Bla bla bla ...";
  }
};

然后我可以这样使用它:

class MyClassFunctor {
public:
  void operator()(MyClass *ptr) const {
    cout << "Deleting ptr using functor: ";
    ptr->describe();
    cout << endl;
    delete ptr;
  }
};

int main() {
  MyClass *myclass = new MyClass();
  MyClassFunctor functor();
  {
    Holder<MyClass> holder(myClass, functor);
  }
  cout << "I'm out of context now!" << endl;
}

AND(不是或)这样:

void myClassDeleter(MyClass *ptr) {
  cout << "Deleting ptr using function pointer: ";
  ptr->describe();
  cout << endl;
  delete ptr;
}

int main() {
  MyClass *myclass = new MyClass();
  {
    Holder<MyClass> holder(myClass, &myClassDeleter);
  }
  cout << "I'm out of context now!" << endl;
}

注意我希望能够使用这两种方法:Functors和函数指针。

我认为这是可能的,因为这是Boost :: shared ptr和tr1 :: shared_ptr所做的。 我试着深入研究Boost :: shared_ptr代码,但我真的不明白他们是怎么做的。

如果我的代码错误或似乎天真,我很抱歉。我试着尽可能简洁地解释这个问题,所以代码的正确性不是我的主要关注点(我意识到这很重要)。

注意我甚至不考虑从头开始重写智能指针类。这是不可能的,因为我知道这不是一个明智的选择。 我很想知道如何做到这一点,所以我可以将这个机制用于其他目的。智能指针只是我记忆中最简单的用法。

目前,我想避免使用boost和C ++ 11。可以使用普通的c ++ 03吗?

非常感谢你的时间。

2 个答案:

答案 0 :(得分:1)

答案是:输入Erasure。

实现并不那么简单,我建议稍微阅读一下Type Erasure(正如我刚才所做的那样!)。

首先,您需要创建Type Erased设备:

class ActionBase {
    public:
        virtual ~ActionBase() { }
        virtual bool DoIt() = 0;
};

template<typename P>
class ActionP : public ActionBase {
    private:
        P *ptr;
    public:
        ActionP(P *p) : ptr(p) { }

        virtual bool DoIt() {
            cout << "Standard action (nothing to do)..." << endl;
            return true;
        }
};

template<typename P, class A>
class ActionPA : public ActionBase {
    private:
        P *ptr;
        A action;

    public:
        ActionPA(P *p, A & a ) : ptr(p), action(a) { }

        virtual bool DoIt() { return action(ptr); }
};

然后你可以声明Holder类:

template<typename T>
class Holder {
    private:
        // Avoid object copy and assignment.
        Holder(const Holder<T> &rhs);
        Holder<T>& operator=(const Holder<T> &rhs);

    protected:
        T* ptr;
        ActionBase *action;

    public:
        template<typename U> Holder(U *ptr) : ptr(ptr), action(new ActionP<U>(ptr)) { }

        template<typename U, class A> Holder(U* p, A a) : ptr(p), action(new ActionPA<U, A>(p, a)) { }

        virtual ~Holder() { delete ptr; delete action; }

        bool DoAction() {
            return this->action->DoIt();
        }
};

然后你可以使用它传递函数指针,仿函数,甚至没有:

template<typename T>
class ActionFunctor {
    public:
        bool operator()(T* instance) const {
            cout << "Action operator..." << endl;
            // Simple operation: set the value to 3 times the original value (works for int and string!!)
            instance->Set(instance->Get() + instance->Get());
            return true;
        }
};

template<typename T>
bool ActionFunc(T* instance) {
    cout << "Action function..." << endl;
    // Simple operation: set the value to 3 times the original value (works for int and string!!)
    instance->Set(instance->Get() + instance->Get() + instance->Get());
    return true;
}

int main() {
    {
        cout << "First test:" << endl;
        ActionFunctor<X> actionX;
        Holder<X> x1(new X(1), &ActionFunc<X>);
        Holder<X> x2(new X(10), actionX);
        Holder<X> x3(new X(100));
        x1.DoAction();
        x2.DoAction();
        x3.DoAction();
    }
    {
        cout << "Second test:" << endl;
        ActionFunctor<Y> actionY;
        Holder<Y> y1(new Y("A"), &ActionFunc<Y>);
        Holder<Y> y2(new Y("BB"), actionY);
        Holder<Y> y3(new Y("CCC"));
        y1.DoAction();
        y2.DoAction();
        y3.DoAction();
    }

    return 0;
}

这是输出:

First test:
X constructor: 1
X constructor: 10
X constructor: 100
Action function...
Action operator...
Standard action (nothing to do)...
X desstructor: 100
X desstructor: 20
X desstructor: 3
Second test:
Y constructor: "A"
Y constructor: "BB"
Y constructor: "CCC"
Action function...
Action operator...
Standard action (nothing to do)...
Y destructor: "CCC" ...
Y destructor: "BBBB" ...
Y destructor: "AAA" ...

希望它对其他人有用。

答案 1 :(得分:0)

一个明显的解决方案是使用boost::functionstd::function。但是,如果要避免这些对象添加的开销,可以使Holder接受 Callable 作为模板参数:

template <typename T, class F> 
class Holder 
{
private:
  T *m_ptr;
  F m_func;
//...

当然,你必须制作一个帮助函数来扣除 Callable 的实际类型:

// depending on the nature of your functors, consider passing by const &
template<typename T, class F>
Holder<T, F> make_holder(T *t, F f)
{
  return Holder<T, F>(t, f);
}

像这样使用:

auto holder = make_holder(myClass, &myClassDeleter);
// or:
auto holder = make_holder(myClass, functor);