Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to change a function pointer (std::function) inside a called function?

I have a std::function pointing to a function. Inside this function I change the pointer to another function.

std::function<void()> fun;

void foo() {
    std::cout << "foo\n";
}

void bar() {
    std::cout << "bar\n";
    fun = foo;
}

int main() {
    fun = bar;
    fun();
    fun();
}

I can't see any problem and it works just fine (see here), however I'm not sure if this is legal to do so. Is there anything I am missing? Maybe in the c++ standard draft (I checked quickly but didn't see anything so far).

like image 219
user1810087 Avatar asked Mar 07 '17 14:03

user1810087


People also ask

Is std :: function a function pointer?

They are not the same at all. std::function is a complex, heavy, stateful, near-magic type that can hold any sort of callable entity, while a function pointer is really just a simple pointer. If you can get away with it, you should prefer either naked function pointers or auto - bind / auto -lambda types.

What can not be done with function pointers?

2. What will we not do with function pointers? Explanation: As it is used to execute a block of code, So we will not allocate or deallocate memory.

Can we declare a function that can return a pointer to a function of the same type?

Return Function Pointer From Function: To return a function pointer from a function, the return type of function should be a pointer to another function. But the compiler doesn't accept such a return type for a function, so we need to define a type that represents that particular function pointer.

Are function pointers safe?

They are potentially dangerous if misused since program execution can go to unwanted location. In fact, coding standards like MISRA C (e.g. rule 104) forbid the use of variable function pointers. If you are using function pointers, it can be tricky to figure out where they are pointing to.


1 Answers

This is legal with function pointers.

When you assign or construct a std::function with a target, it creates a copy of the target. In the case of assigning a function to the std::function, this in effect stores a function pointer as the target object.

When you invoke operator(), it is required to return what would happen if you invoked that the target with the arguments.

Within that "body" of the copy of the function object stored as a copy in the std::function, if you reassign to the std::function, this destroys the old target function object.

Destroying a function pointer has no impact on the validity of code executed within the function pointed to.

However, if you had stored function objects (lambdas, manual ones, other std::functions, std::bind, etc), at the point of assignment you'd run into the usual rules of running a method in a class when this is destroyed. In short, you would no longer be able to do anything that relied on "local state" of your instance.

std::function<void()> fun;
struct bob {
  std::string name;
  bob* next = 0;
  void operator()() const {
    std::cout << name << "\n";
    if (next) fun = *next;
    // undefined behavior:
    // std::cout << name << "\n";
  }
};
bob foo = {"foo"};
bob bar = {"bar", &foo};

int main() {
  fun = bar;
  fun();
  fun();
}

live example.

So as you can see, this can be fragile.

like image 182
Yakk - Adam Nevraumont Avatar answered Sep 28 '22 12:09

Yakk - Adam Nevraumont