Reputation: 297
Let me demonstrate what I mean.
#include <functional>
#include <iostream>
class MyClass
{
private:
int number;
public:
MyClass()
{
number = 0;
}
void printNumber()
{
std::cout << "number is " << number << std::endl;
number++;
}
};
int main()
{
std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
auto function = std::bind(&MyClass::printNumber, obj);
function();
// This deallocates the smart pointer.
obj.reset();
// This shouldn't work, since the object does not exist anymore.
function();
return 0;
}
This outputs:
number is 0
number is 1
If we were to call the function like we would normally, replacing "function()" with "obj->printNumber()", the output is:
number is 0
Segmentation fault: 11
Just like you would expect it to be.
So my question is if there is any way to make sure that we are unable to call the function when the object has been deallocated? This has nothing to do with using smart pointers, it works the same way with regular pointers.
Upvotes: 0
Views: 1616
Reputation: 23793
Is there any way to check if an
std::function points
to a member of a valid object?
std::function
does not point to a "member of an object", it encapsulates a Callable. When you bind it with an object, you get another callable object (of unspecified type actually), that can be stored in an std::function
So my question is if there is any way to make sure that we are unable to call the function when the object has been deallocated?
No, there is no way. But as noted by ecatmur, since std::bind
copies it's argument(s), you are fine in your example.
Upvotes: 3
Reputation: 44258
"This has nothing to do with using smart pointers, it works the same way with regular pointers."
This statement is incorrect. obj->printNumber() with smart pointer fails not because object is destroyed, but because this particular instance of shared pointer obj
does not point to a valid object anymore. If you try to do this with raw pointers:
MyClass *obj = new MyClass;
auto function = std::bind(&MyClass::printNumber, obj);
function();
delete obj;
// This will have UB
function();
you will get completely different situation (undefined behavior) of using an object after destruction and memory deallocation.
There is no way in C++ to validate that raw pointer points to a valid object. But what you can use is a std::weak_ptr
. It will not work directly with std::bind
so you may want to write a lambda or a simple wrapper, where you would check that object is still valid:
auto wrapper = []( std::weak_ptr<MyClass> wobj ) { auto obj = wobj.lock(); if( obj ) obj->printNumber(); };
auto function = std::bind( wrapper, std::weak_ptr<MyClass>( obj ) );
Upvotes: 0
Reputation: 157364
Your code is valid.
obj.reset()
does not deallocate the shared MyClass
object, because a copy of the shared pointer obj
exists within the bind-expression function
. This is because std::bind
copies (or moves) its arguments, unless wrapped in reference_wrapper
(e.g. by std::ref
).
If you instrument or place a breakpoint on the destructor of MyClass
, you will find it is not called until the end of main
, when the local variable function
is destructed.
Upvotes: 6