C++回调,模板成员?(2)

Gio*_*hal 2 c++ templates memory-management callback pointer-to-member

以下回调类是"可调用事物"的通用包装器.我真的很喜欢它的API,它没有模板而且非常干净,但是引擎盖下有一些我无法避免的动态分配.

在维护回调类的语义和API的同时,有没有办法摆脱下面的代码中的newdelete?我真的希望我能.


需要的东西:

// base class for something we can "call"
class callable {
  public:
  virtual void operator()() = 0;
  virtual ~callable() {}
};

// wraps pointer-to-members
template<class C>
class callable_from_object : public callable {
  public:
  callable_from_object(C& object, void (C::*method)())
         : o(object), m(method) {}

  void operator()() {
    (&o ->* m) ();
  }
  private:
  C& o;
  void (C::*m)();
};

// wraps pointer-to-functions or pointer-to-static-members
class callable_from_function : public callable {
   public:
   callable_from_function(void (*function)())
         : f(function) {}

   void operator()() {
      f();
   };
   private:
   void (*f)();
};
Run Code Online (Sandbox Code Playgroud)

回调类:

// generic wrapper for any callable
// this is the only class which is exposed to the user
class callback : public callable {
   public:
   template<class C>
   callback(C& object, void (C::*method)())
         : c(*new callable_from_object<C>(object, method)) {}
   explicit callback(void (*function)())
         : c(*new callable_from_function(function)) {}
   void operator()() {
      c();
   }
   ~callback() {
      std::cout << "dtor\n"; // check for mem leak
      delete &c;
   }
   private:
   callable& c;
};
Run Code Online (Sandbox Code Playgroud)

一个API示例:

struct X {
  void y() { std::cout << "y\n"; }
  static void z() { std::cout << "z\n"; }
} x;

void w() { std::cout << "w\n"; }

int main(int, char*[]) {
   callback c1(x, &X::y);
   callback c2(X::z);
   callback c3(w);
   c1();
   c2();
   c3();
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

非常感谢 !!:-)

Joh*_*itb 5

您可以使用新的展示位置.比如,设置您希望允许的最大大小限制callback,如16字节.然后,unsigned char在你的callback类中放一个缓冲区,确保它正确对齐(GCC有一个属性,如果你很幸运,微软也有一个属性).

如果你使用一个联合,你也可以相当安全,并且在char缓冲区旁边放入你想要填充的类型的假人 - 这也将确保正确的对齐.

然后,使用placement new,而不是使用普通的new

if(placement_allocated< callable_from_object<C> >::value) {
  new ((void*)buffer.p) // union member p is the unsigned char buffer
    callable_from_object<C>(object, method);
  c = (callable*)buffer.p;
} else {
  c = new callable_from_object<C>(object, method);
}
Run Code Online (Sandbox Code Playgroud)

然后,使c成员成为指针.您还需要设置一个标志,以便记住是否必须在析构函数中调用delete,或者在显式调用析构函数时单独放置放置缓冲区.

基本上是怎么回事boost::function.然而,它还有很多其他的东西来优化分配.它使用自己的vtable机制来优化空间,当然也经过了很好的测试.

当然,这并不容易.但这似乎是唯一要做的事情.