我的问题相当简单:如何在不传递this
的情况下获取指向调用函数的对象的指针?
然而,我要问的原因稍微复杂一些。
我被问到这是因为我正在编写一个类(名为SubordnateRegistry
),它包含一个函数委托的异构列表(列表) - 具有不同签名的可调用对象。
无论哪个类希望有代表调用,都必须注册自己,当然,还要注册他们希望接收的数据类型,以及指向对象的指针或已经构造的委托。来自类Bar
内部的调用可能如下所示:
ARegistry.Subscribe <Foo> (& Bar:: BarFunction, this);
或者像这样:
using namespace std:: placeholders;
auto Func = std:: bind (& Bar:: BarFunction, this, _1);
ARegistry.Subscribe <Foo> (Func);
因为std:: function
更通用(你可以绑定任何可调用的,包括lambdas),我宁愿在原始指针上使用它。
我的问题在于我必须始终指定this
。如果我传递了一个无效指针,或者最终注册了一个完全不相关的对象,那么我将来会在某个不确定的位置调用UB而不知道它来自哪里或错误的根源在哪里。讨厌!
现在,如果你想知道如果调用者不是一个对象(一个自由函数)会发生什么,那么该元素将永远保持注册状态,因为我永远不会自动删除(取消注册)可调用对象,因为它永远不会破坏。
任何想法,或者这是不可能的,因为我被引导相信?预处理器魔术是一种选择吗?有没有更好的办法?
当然,欢迎任何问题。谢谢你的时间 :)。
答案 0 :(得分:1)
例如,您可以使用#define自动包含this
。
#define REG_SUBSCRIBE(t,f) ARegistry.Subscribe <t> (f, this)
当然,这可能会变得很难看,所以我不知道我是否会推荐它。
如果您担心跟踪并释放它们,那么我建议使用析构函数返回一个取消订阅该对象的对象。或者(或另外)提供方法调用来执行此操作。
答案 1 :(得分:1)
我使用奇怪的重复模板模式给了它一个镜头。我们的想法是将一个方法的注册封装在一个类中,该类的析构函数将在销毁时自动注销客户端对象。客户端派生自此类。这样,析构函数将自动调用,注册类具有对客户端this
指针的隐式访问权限。因此没有必要明确地通过它。
在这个答案中,我将假设以下访客类:
// The visitor class. Clients can register methods here.
class Visitor {
public:
// Expects void(void) methods.
template <class T>
using method_t = void (T::*)();
// Register a new method of a client.
template <class T>
void subscribe(method_t<T> method, T* object);
// unsubscribe all methods of a given client.
template <class T>
void unsubscribe(T* object);
};
注册类如下所示:
// CRTP registration class.
// Will automatically subscribe and unsubscribe its base class.
template <class Derived>
class Registration {
public:
// The constructor takes a reference to the visitor,
// and a pointer to the method that should be registered.
// It will then register this particular method.
Registration(Visitor &visitor, Visitor::method_t<Derived> method)
: visitor_(visitor) {
visitor_.subscribe(method, static_cast<Derived *>(this));
}
// The destructor calls the visitors unsubscribe method unregistering
// all methods of this particular client.
virtual ~Registration() {
visitor_.unsubscribe(static_cast<Derived *>(this));
}
private:
Visitor &visitor_;
};
实际的客户端看起来像这样。
// A client using the registration class.
// Has to inherit publically, otherwise the `this` pointer cast will fail.
class Client : public Registration<Client> {
public:
Client(Visitor &visitor)
: Registration<Client>(visitor, &Client::method) {}
void method();
};
您可以找到一个示例用法here。
Registration
类可以在公共可用的成员函数中注册方法而不是构造函数。如果由于某种原因,您需要多次从Registration
继承,请考虑将对访问者和基类链的引用分解出来。