C++ function
简单记录下编写代码时遇到的问题:
在调用一个接口的时候,需要传入一个std::function类型的参数。
之前在调用此接口时传入的参数lambda表达式类型。由于接口的定义为function<void()>类型,而在调用传入参数时,需要遍历数组,处理数组中的成员。若采用lambda的方式,只能通过捕获的方式传值,考虑到作用域和lambda之间的干扰,应采用值捕获的方式。代码看起来像这样:
void deal(const function<void()>& func) { func(); } int main(int argc, char* argv[]) { vector<int> nums = { 1,2,3,4 }; for (auto num:nums) { auto func = [num]() { cout << num << endl; }; deal(func); } return 0; }
实际的处理func处理过程很复杂,将lambda表达式在for循环中定义,代码段过长。而且此函数是多次定时调用,涉及到内存分配, 采用lambda需要每次重新分配内存,每次使用完之后释放,效率较低。
改为使用仿函数,则代码如下:
class A { public: A(int num):_num(num) {} void operator()() { std::cout << _num << std::endl; } private: int _num; }; void deal(const function<void()>& func) { func(); } int main(int argc, char* argv[]) { vector<int> nums = { 1,2,3,4,5,6 }; for (auto num:nums) { A a(num); deal(a); } return 0; }
需要注意的是:
在构造function时,会对仿函数进行拷贝构造和移动构造,在VS2019中的实现如下:
template <class _Fx, typename _Mybase::template _Enable_if_callable_t<_Fx&, function> = 0> #else // ^^^ _USE_FUNCTION_INT_0_SFINAE // !_USE_FUNCTION_INT_0_SFINAE vvv template <class _Fx, class = typename _Mybase::template _Enable_if_callable_t<_Fx&, function>> #endif // _USE_FUNCTION_INT_0_SFINAE function(_Fx _Func) { this->_Reset(_STD move(_Func)); }
即:在构造function时,先按值传递仿函数对象,调用一次拷贝构造函数,在function函数内部再调用移动构造函数。实现仿函数时,若涉及到内存申请释放,应自定义拷贝构造函数和移动构造函数,避免浅拷贝引起的问题。
编译器默认生成的拷贝构造函数和移动构造函数相关问题参见:
https://www.cnblogs.com/yajiu/articles/15435277.html