3
std::function<void(bool)> f;
std::function<void()> binded_f = std::bind(f, true);
std::cout << (f != nullptr) << " " << (binded_f != nullptr) << "\n";
f(true);
binded_f();

Above code gave output 0 1, and binded_f() crash with Unhandled exception at 0x00007FFE7B63A388 in: Microsoft C++ exception: std::bad_function_call at memory location 0x00000096960FA660. occurred in MSVC.

Seems calling the null function f is fine, while after std::bind applied, it will crash. What should we do? Do we need check a function before binded?

JeJo
  • 30,635
  • 6
  • 49
  • 88
heLomaN
  • 1,634
  • 2
  • 22
  • 33

2 Answers2

3

Seems calling the null function enter code here f is fine, while after std::bind applied, it will crash. What should we do?

No, both

f(true);
binded_f();

will through exception, and you see the exception from the first function call (i.e. f(true);) itself. From cppreference.com std::function::operator()

Exceptions

std::bad_function_call if *this does not store a callable function target, i.e. !*this == true.

Meaning, the call of f is clearly an exception.

Also for std::bind

Exceptions

Only throws if construction of std::decay<F>::type from std::forward<F>(f) throws, or any of the constructors for std::decay<Arg_i>::type from the corresponding std::forward<Arg_i>(arg_i) throws where Arg_i is the ith type and arg_i is the ith argument in Args... args.

Since the construction of f throws/ fails, the binded object will also through exception upon call.


Do we need to check a function before binded?

Yes, for the reasons mentioned above.

JeJo
  • 30,635
  • 6
  • 49
  • 88
1

The std::bad_function_call already happens at f(true).

You need to check if f holds a function on both cases when calling f and before you call std::bind on it.

std::bind expects a Callable object and std::function<void(bool)> f itself is a callable object. But calling f is only valid if it holds a target, as it will forward the call using std::forward to the stored target when f is called.

std::function<void()> binded_f holds a target that will call the stored copy of f with true as the first argument, so binded_f itself holds a valid target, but that target, when it tries to call f with true will fail result into a std::bad_function_call because f does not hold a valid target.

This becomes more obvious if you replace the bind with a lambda.

std::function<void(bool)> f;
std::function<void()> binded_f = [f]() {
   return f(true);
};

std::cout << (f != nullptr) << " " << (binded_f != nullptr) << "\n";
f(true);
binded_f();
t.niese
  • 39,256
  • 9
  • 74
  • 101