目录- 1.std::bind是什么?
- 2. 核心机制:占位符 (std::placeholders)
- 3. 代码实战
- 场景 A:固定参数(减少参数个数)
- 场景 B:参数重排(改变参数顺序)
- 场景 C:绑定成员函数(最常用的旧式写法)
- 4. 这里的坑:参数拷贝 vs 引用
- 5. 灵魂拷问:为什么现在不推荐用std::bind?
1.std::bind是什么?
简单来说,std::bind 是一个函数适配器(Adapter)。
核心作用是“预先固定”一个函数的某些参数,从而生成一个新的函数对象。
你可以把它想象成一个模具:原来的函数需要 3 个原料,你先塞进去 1 个固定的原料,剩下的 2 个留空(占位),这就变成了一个只需要 2 个原料的新工具。
2. 核心机制:占位符 (std::placeholders)
要使用 std::bind,必须先认识它的搭档:占位符。
它们位于 std::placeholders 命名空间下,通常写成 _1, _2, _3...
_1:代表新函数被调用时的第 1 个参数。_2:代表新函数被调用时的第 2 个参数。- 以此类推。
3. 代码实战
我们需要包含头文件:
#include <functional>
using namespace std::placeholders; // 方便使用 _1, _2
场景 A:固定参数(减少参数个数)
假设你有一个减法函数,你希望得到一个“减去 10”的专用函数。
#include <iostream>
#include <functional>
using namespace std::placeholders;
int sub(int a, int b) {
return a - b;
}
int main() {
// 使用 bind:
// 我们把 sub 的第二个参数 b 固定死为 10
// _1 代表新函数 sub_ten 的第一个参数,它会被填入 sub 的第一个位置 a
auto sub_ten = std::bind(sub, _1, 10);
// 调用新函数:
// 实际执行的是: sub(20, 10)
std::cout << sub_ten(20) << std::endl; // 输出 10
return 0;
}
场景 B:参数重排(改变参数顺序)
std::bind 甚至可以颠倒参数的顺序。
// 还是上面的 sub(a, b) -> a - b
// 这次我们交换位置:
// sub 的第一个参数 (a) 吃新函数的第二个参数 (_2)
// sub 的第二个参数 (b) 吃新函数的第一个参数 (_1)
auto reverse_sub = std::bind(sub, _2, _1);
// 调用: reverse_sub(10, 20)
// 实际执行: sub(20, 10) -> 20 - 10
std::cout << reverse_sub(10, 20) << std::endl; // 输出 10
场景 C:绑定成员函数(最常用的旧式写法)
这是 std::bind 在 C++11 初期最常见的用途:配合 std::function 做回调,特别是为了绑定 this 指针。
class Hero {
public:
void heal(int amount) {
std::cout << "Healed " << amount << " hp." << std::endl;
}
};
int main() {
Hero myHero;
// 绑定成员函数
// 参数1:成员函数指针 &Hero::heal
// 参数2:对象实例的地址 &myHero (作为隐式的 this)
// 参数3:占位符 _1 (将来传进来的 amount)
std::function<void(int)> func = std::bind(&Hero::heal, &myHero, _1);
func(50); // 输出: Healed 50 hp.
}
4. 这里的坑:参数拷贝 vs 引用
这是 std::bind 最容易出错的地方。std::bind 默认是按值拷贝参数的!
如果你想绑定的参数是一个引用,或者是一个无法拷贝的对象
(比如 unique_ptr),你必须显式使用 std::ref 或 std::cref (const ref)。
void updateScore(int& score, int val) {
score += val;
}
int main() {
int myScore = 100;
// 错误写法!
// auto update = std::bind(updateScore, myScore, _1);
// 这会导致 bind 内部拷贝了一份 myScore,原本的 myScore 不会变。
// 正确写法:使用 std::ref
auto update = std::bind(updateScore, std::ref(myScore), _1);
update(20);
std::cout << myScore << std::endl; // 输出 120
}
5. 灵魂拷问:为什么现在不推荐用std::bind?
既然 Lambda 讲完了,Bind 也讲完了,我们对比一下。现在 C++ 社区(包括官方指南)强烈建议能用 Lambda 就别用 Bind。
原因如下:
- 可读性差:
bind(func, _2, 10, _1) 这种写法像是猜谜语,你需要脑补参数填空的对应关系。而 Lambda [](int x, int y) { return func(y, 10, x); } 一目了然。 - 容易出错:刚才提到的
std::ref 问题,很容易忘记写,导致很多隐晦的 Bug。而 Lambda 的捕获列表 [&] 显式且直观。 - 编译器优化:Lambda 表达式对编译器来说是透明的代码块,容易内联优化。
std::bind 生成的是复杂的模板对象,编译器优化起来比较费劲,有时会导致生成的二进制代码更大、更慢。
对比示例:
// 任务:调用 object.process(data)
// 方式 1: std::bind (旧时代)
auto task1 = std::bind(&MyClass::process, &object, data);
// 方式 2: Lambda (新时代 - 推荐)
auto task2 = [&object, data]() { object.process(data); };
到此这篇关于C++中的bind代码实践的文章就介绍到这了,更多相关C++ bind内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!
您可能感兴趣的文章:- C++/Python混合编程之小结Pybind11的使用
- python使用Pybind11扩展c++的实现
- C++11 std::function和std::bind 的使用示例详解
- C++ ROS与boost:bind()使用详解
- C++11中bind绑定器和function函数对象介绍
- c++中的bind使用方法
- C++ std::bind用法详解
- C++中使用function和bind绑定类成员函数的方法详解
|