Search code examples
c++stdmove

What does std::move do when called on a function?


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?


Solution

  • 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}