#include <functional>
#include <iostream>
using namespace std;
class test {
public:
test(){ p = new int[10];}
void print_info(double a)
{
cerr << a << endl;
}
~test(){
cerr << __LINE__ << endl;
delete []p;
}
private:
int *p;
};
int main()
{
test t;
std::function<void(void)> f = std::bind(&test::print_info, t, 2.0);
//std::function<void(void)> f = std::bind(&test::print_info, std::cref(t), 2.0);
return 0;
}
它会崩溃,因为test::~test()
被调用两次。但是,如果我将t
替换为std::cref(t)
(或std::ref(t), &t
),则在退出main()时只会调用~test()
一次。
我没弄清楚原因。我在Ubuntu 12.04 64bit上,使用gcc 4.6.3。
答案 0 :(得分:8)
您正在绑定对象t
的副本。由于您的类尝试管理动态内存,但不遵循Rule of Three,因此它具有无效的复制语义 - 两个副本都会尝试在销毁时删除相同的动态数组。
如果您使用类似std::vector
的类(具有有效的复制语义)来管理动态数组,那么一切都会没问题。
答案 1 :(得分:4)
由于你绑定了一个copy of object t
,而不是t
本身,当从bind
对象返回时将会被破坏,因为你没有超载copy c-tor,默认复制c-tor将进行浅层复制,您的p
将被删除两次。对于绑定t
本身,您应该使用std::ref
。
答案 2 :(得分:0)
std::function<void(void)> f = std::bind(&test::print_info, t, 2.0);
它会崩溃,因为test :: ~test()被调用两次。但是,如果我用std :: cref(t)(或std :: ref(t),&amp; t)替换t,那么在退出main()时,只会调用一次~test()。
我没弄清楚原因。我在Ubuntu 12.04 64bit上,使用gcc 4.6.3。
原因实际上非常简单,std::bind
函数创建了一个包含参数副本的仿函数对象。在你的程序中有一个错误,复制该类型的对象最终会有两个对象,这些对象具有指向同一内存的指针,并且都在其析构函数中调用delete[]
。
绑定&t
时,会复制对象(指针)的地址。没有两个单独的对象,只有一个对象和一个指针。类似地,实用程序std::ref
和std::cref
是引用包装器,即包装不同对象并提供类似引用的语义的对象。无论复制std::ref
多少次,所有副本都表现为对同一对象的引用。永远不会复制对象本身。