I'm working on making some changes to a piece of code, and have a doubt in understanding the behavior of std::move in below case:
struct Timer {
Timer (boost::asio::io_service& ios) : timer_{ios} {}
boost::asio::steady_timer timer_;
};
struct TimerContext {
void *ctxt_;
};
class A {
std::function<void(Timer *, const TimerContext&)> callback_;
boost::asio::io_service ios_;
};
A's constructor:
A::A (std::function<void(Timer *, const TimerContext&)> cb) : callback_{std::move(cb)}
{
}
The callback function definition:
void
customCallback (Timer *timer, const TimerContext& ctxt) {
...
}
In main()
,
for (int i = 0; i < 5; ++i) {
A *a = new A{customCallback};
}
My doubt is for this line:
A::A (std::function<void(Timer *, const TimerContext&)> cb) : callback_{std::move(cb)}
Class A is getting instantiated in a loop, and the same customCallback
function is getting moved to the custom constructor for each new object.
Will the first std::move not make callback function unusable for next call? As I understood, if you use std::move(t)
, then t
cannot be used again in that scope.
I'm confused what is happening internally here for all 5 calls to std::move(cb)
on the same function in new A
. Is this the right way to do how it is implemented?
Look carefully at A's constructor:
A::A (std::function<void(Timer *, const TimerContext&)> cb)
The function, cb
is being passed by value. That means a copy of the function has already occurred from when it was invoked via new:
A *a = new A{customCallback};
The std::move
in the constructor initializer list exists to avoid a redundant copy into the member variable. The original function defined by the caller who invoked new A
remains unmoved. This is preferred because copying a std::function
variable can be expensive. (sizeof(cb)
- might be way bigger than you expected).
An alternative implementation: The function could have been passed as a const reference and allow the copy to occur in the constructor itself:
A::A (const std::function<void(Timer *, const TimerContext&)>& cb) : callback_{cb}