2
#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()被调用了两次。但是,如果我替换tstd::cref(t)(或std::ref(t), &t), ~test()则在退出 main() 时将只调用一次。

我没有弄清楚原因。我在 Ubuntu 12.04 64bit 上,使用 gcc 4.6.3。

4

3 回答 3

8

您正在绑定 object 的副本t。由于您的类尝试管理动态内存,但不遵循三规则,因此它具有无效的复制语义 - 两个副本都将尝试在销毁时删除相同的动态数组。

如果您使用std::vector具有有效复制语义的类来管理动态数组,那么一切都会好起来的。

于 2013-11-08T12:42:24.217 回答
4

由于您绑定的是 a copy of object t,而不是t自身,因此从bindobject 返回时将被破坏,并且由于您没有重载复制 c-tor,因此默认复制 c-tor 将进行浅拷贝,并且您p将被删除两次。对于绑定t本身,您应该使用std::ref.

于 2013-11-08T12:39:23.140 回答
0
std::function<void(void)> f = std::bind(&test::print_info, t, 2.0);

它会崩溃,因为 test::~test() 被调用了两次。但是,如果我将 t 替换为 std::cref(t)(或 std::ref(t),&t),则在退出 main() 时将只调用一次 ~test()。

我没有弄清楚原因。我在 Ubuntu 12.04 64bit 上,使用 gcc 4.6.3。

原因其实很简单,该std::bind函数创建了一个函子对象来保存参数的副本。在您的程序中存在一个错误,并且复制该类型的对象最终会导致两个对象具有指向相同内存的指针并且都调用delete[]它们的析构函数。

当您绑定对象(指针)&t地址时,将被复制。没有两个独立的对象,只有一个对象和一个指针。同样,实用程序std::refstd::cref引用包装器,即包装不同对象并提供类似引用语义的对象。无论std::ref复制多少次,所有副本都表现为对同一对象的引用。对象本身永远不会被复制。

于 2013-11-08T13:59:30.360 回答