I have been debugging an issue involving an std::function
(created from std::bind
) where the issue boils down to a more fundamental question.
An example follows below, but in short it's about the case when a class in one way or another stores a pointer to itself (or an instance variable) in its constructor and the class itself is then reassigned. From my experiments it seems the stored pointer will then no longer point to the class (or its instance variable). I wonder what are the best practices to avoid these issues?
An example:
#include <iostream>
class Interface
{
public:
Interface() {};
virtual ~Interface() {};
virtual void callback() = 0;
};
class B
{
public:
B() : interface(NULL) {};
virtual ~B() {};
void set_interface(Interface* interface)
{
this->interface = interface;
}
void print()
{
std::cout << "B is at: " << this << std::endl;
std::cout << " Interface (A) from B is at: " << interface << std::endl;
}
private:
Interface* interface;
};
class A : public Interface
{
public:
A()
{
b.set_interface(this);
};
virtual ~A() {};
virtual void callback()
{
std::cout << "Callback" << std::endl;
}
void print()
{
std::cout << "A is at: " << this << std::endl;
b.print();
}
private:
B b;
};
int main(int argc, char** argv)
{
A a;
a.print();
std::cout << "------" << std::endl;
a = A();
a.print();
return 0;
}
When I run this on my machine I get:
A is at: 0x7ffdb8910af0
B is at: 0x7ffdb8910af8
Interface (A) from B is at: 0x7ffdb8910af0
------
A is at: 0x7ffdb8910af0
B is at: 0x7ffdb8910af8
Interface (A) from B is at: 0x7ffdb8910b10
So, at first everything is fine. The pointer to Interface from B
points to the address of A
. However, after reassigning (a=A()
) the pointer to Interface no longer points to A
! I realize this is because as the constructor of A
is running to create the second instance, it is in a new memory location and stores the interface pointer to this new memory location. When a is then reassigned the object is moved in to the old location which invalidates the pointer to Interface.
This seems like a common use case to me. Should one always avoid referencing memory in constructors of objects?
In my case I would like to bind a callback function and pass it to a class member, it seems I cannot do it in the constructor then and must do it at a later time?