为什么需要引用的函数与指针一起工作?
Why does a function expecting a reference work with a pointer?
我正在用 C++ 编写一个使用 C 库的程序。这个库接受回调函数的指针,我希望它调用实例方法。幸运的是,该库采用了一个额外的数据参数,该参数只是一个 "void *" 并原封不动地传递给回调。所以,我创建了一个通用的回调包装函数。
void callbackWrapper(std::function<void ()> &func) {
func();
}
现在,当我需要在库中注册回调时,我传递一个指向 callbackWrapper 函数的指针作为要调用的函数,并传递一个指向 std::function 的指针作为额外数据参数。当回调发生时,它会调用我的包装器,然后它会调用我真正想调用的实际 method/lambda/whatever。
但是,上面的代码中有一个错误。我使用“&”而不是“*”,这意味着该函数需要 reference 到 std::function,而不是指针。函数应该定义如下:
void callbackWrapper(std::function<void ()> *func) {
(*func)();
}
我有一段时间没有注意到这个错误 -- 因为它工作得很好。我之所以注意到是因为我正在追踪一个不相关的错误,并且恰好看到了它。所以,我的问题是,为什么?我有三个可能的答案:
- C++ 标准允许在这种情况下自动提升指向引用的指针。
- 我的编译器 (gcc 9.3.1) 注意到不匹配并默默地为我修复它。
- 指针的地址刚好落在调用成功的堆栈帧中的正确位置。
我的理论是否正确?如果不是,发生了什么?
情况 3 很可能适用于您的示例。
像传递指针一样传递引用是非常明智的,大多数 ABI 都可能这样做。
例如,Itanium C++ ABI says(这是在 Linux/x64 上使用的 ABI):
Reference parameters are handled by passing a pointer to the object bound to the reference.
我正在用 C++ 编写一个使用 C 库的程序。这个库接受回调函数的指针,我希望它调用实例方法。幸运的是,该库采用了一个额外的数据参数,该参数只是一个 "void *" 并原封不动地传递给回调。所以,我创建了一个通用的回调包装函数。
void callbackWrapper(std::function<void ()> &func) {
func();
}
现在,当我需要在库中注册回调时,我传递一个指向 callbackWrapper 函数的指针作为要调用的函数,并传递一个指向 std::function 的指针作为额外数据参数。当回调发生时,它会调用我的包装器,然后它会调用我真正想调用的实际 method/lambda/whatever。
但是,上面的代码中有一个错误。我使用“&”而不是“*”,这意味着该函数需要 reference 到 std::function,而不是指针。函数应该定义如下:
void callbackWrapper(std::function<void ()> *func) {
(*func)();
}
我有一段时间没有注意到这个错误 -- 因为它工作得很好。我之所以注意到是因为我正在追踪一个不相关的错误,并且恰好看到了它。所以,我的问题是,为什么?我有三个可能的答案:
- C++ 标准允许在这种情况下自动提升指向引用的指针。
- 我的编译器 (gcc 9.3.1) 注意到不匹配并默默地为我修复它。
- 指针的地址刚好落在调用成功的堆栈帧中的正确位置。
我的理论是否正确?如果不是,发生了什么?
情况 3 很可能适用于您的示例。
像传递指针一样传递引用是非常明智的,大多数 ABI 都可能这样做。
例如,Itanium C++ ABI says(这是在 Linux/x64 上使用的 ABI):
Reference parameters are handled by passing a pointer to the object bound to the reference.