3
#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;
}

It will crash, since test::~test() is called twice. But, if I replace t with std::cref(t) (or std::ref(t), &t), ~test() will be called only once when exiting main().

I didn't figure out the reason. I'm on Ubuntu 12.04 64bit, using gcc 4.6.3.

MSalters
  • 173,980
  • 10
  • 155
  • 350
tfjiang
  • 33
  • 1
  • 3

3 Answers3

9

You're binding a copy of the object t. Since your class tries to manage dynamic memory, but doesn't follow the Rule of Three, it has invalid copy semantics - both copies will try to delete the same dynamic array on destruction.

If you used a class like std::vector, with valid copy semantics, to manage the dynamic array, then all would be fine.

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
4

Since you are binding a copy of object t, not t itself, that will be destructed when returning from bind object will be destructed and since you don't overload copy c-tor, default copy c-tor will make shallow copy and your p will be deleted twice. For binding t itself you should use std::ref.

ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • +1 Which leads us to the problem that the implicitly defined copy-ctor here only makes a shallow copy. (Btw. its definition as defaulted is deprecated in C++11) – dyp Nov 08 '13 at 12:41
0
std::function<void(void)> f = std::bind(&test::print_info, t, 2.0);

It will crash, since test::~test() is called twice. But, if I replace t with std::cref(t) (or std::ref(t), &t), ~test() will be called only once when exiting main().

I didn't figure out the reason. I'm on Ubuntu 12.04 64bit, using gcc 4.6.3.

The reason is actually quite simple, the std::bind function creates a functor object that holds a copy of the arguments. In your program there is a bug and copying objects of the type end up with two objects having pointers to the same memory and both calling delete[] in their destructors.

When you bind &t the address of the object (pointer) gets copied. There are no two separate objects, just one object and a pointer. Similarly the utilities std::ref and std::cref are reference wrappers, that is objects that wrap a different object and provide reference-like semantics. No matter how many times std::ref is copied, all of the copies behave as references to the same object. The object itself is never copied.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489