最近使用boost::bind比较多,发现有一些奇怪的现象。就是在用boost::bind传递引用的时候,如果引用的对象被释放,那么之后的函数执行必然会访问无效的地址儿出错。但是这个担忧是多余的,boost::bind在传递引用的时候,并不是真的传递引用,而是执行对象的拷贝构造函数重新生成了一个全新的对象,测试代码如下:
#include<iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
using namespace std;
class A
{
public:
A(){ i = 0; cout << "A constructor" << endl;}
A(const A& a)
{
i = 0;
cout << "A copay constructor" << endl;
}
int i;
};
typedef boost::function<void (void)> fun;
void myfun(A& a)
{
a.i += 10;
}
int main(int argc, char** argv)
{
A a;
a.i = 0;
fun f(boost::bind(myfun, a));
f();
cout << a.i << endl;//此处输出0,而不是期望的10
return 0;
}
输出结果如下:
A constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
A copay constructor
0
可以看到,A类的构造函数被调用了很多次,这个我也不是很清楚内部的实现逻辑,但是可以清楚的是引用传递没有生效,实际上是生成了一个新的对象。再对新的对象的i进行加10,所以打印出的a对象的i实际上并没有被改变,为0;
这个设计我猜想boost设计者的原意也是担心引用对象被释放,造成引用无效对象而崩溃的问题,因此在传递引用的时候实际上是值传递。
如果真的想传递引用,也是有办法的,boost设计者给了boost::ref这个对象,明确表示我只传递引用,不要拷贝。以上代码可以改成:
fun f(boost::bind(myfun, boost::ref(a)));
更改之后输出为:
A constructor
10
这个就不会重新生成很多对象了,从始至终都只有一个对象
如果明确了引用对象不会被释放,建议使用boost::ref来强制避免拷贝,毕竟那么多对象的构造和析构都是对性能的浪费,也增加了出错的可能性。