Gio*_*hal 2 c++ templates memory-management callback pointer-to-member
以下回调类是"可调用事物"的通用包装器.我真的很喜欢它的API,它没有模板而且非常干净,但是引擎盖下有一些我无法避免的动态分配.
在维护回调类的语义和API的同时,有没有办法摆脱下面的代码中的new和delete?我真的希望我能.
需要的东西:
// 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)
非常感谢 !!:-)
您可以使用新的展示位置.比如,设置您希望允许的最大大小限制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机制来优化空间,当然也经过了很好的测试.
当然,这并不容易.但这似乎是唯一要做的事情.