std :: function包装器,避免动态内存分配

时间:2016-01-04 21:13:57

标签: c++ templates c++14

请考虑以下代码:

#include <functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <time.h>

struct Foo {
  Foo(int x) : x(x) {}
  void func1() const { printf("Foo::func1 x=%d\n", x); }
  void func2() const { printf("Foo::func2 x=%d\n", x); }
  int x;
  char junk[64];
};

struct Bar {
  Bar(int x) : x(x) {}
  void func3() const { printf("Bar::func3 x=%d\n", x); }
  int x;
  char junk[64];
};

void loop(std::function<void()>& g) {
  for (int i=0; i<10; ++i) {
    switch (rand()%3) {
      case 0:
        {
          Foo foo(3);
          g = std::bind(&Foo::func1, foo);
          break;
        }
      case 1:
        {
          Foo foo(4);
          g = std::bind(&Foo::func2, foo);
          break;
        }
      case 2:
        {
          Bar bar(5);
          g = std::bind(&Bar::func3, bar);
          break;
        }
      default: break;
    }
  }
}

int main() {
  srand(time(NULL));
  std::function<void()> g;
  loop(g);
  g();
  return 0;
}

此代码将使用复制的对象实例(已超出范围)执行Foo::func1()Foo::func2()Bar::func3()中的一个。

我想要使用此代码更改的内容是删除loop()中的动态分配。为此,我尝试在std::function周围创建一个包装器,如下所示:

template <typename _Signature> class my_function;

template <typename R, typename... Args>
class my_function<R(Args...)> {
public:
  template<typename T, typename FUNC>
    void bind(FUNC&& func, const T& t) {
      static_assert(sizeof(t) <= sizeof(obj_buffer), "insufficient obj_buffer size");
      static_assert(std::is_trivially_destructible<T>::value, "memory leak");

      auto p = new(obj_buffer) T(t);  // placement new
      auto ref = std::ref(*p);
      f = std::bind(func, ref /* how do I forward variable # of placeholders here??? */);
    }

  R operator()(Args&& ...args) const { return f(std::forward<Args>(args)...); }

private:
  char obj_buffer[1024];
  std::function<R(Args...)> f;
};

然后我将g的声明从std::function<void()>更改为my_function<void()>,并将g = std::bind(x,y)声明替换为g.bind(x,y) loop()内的std::bind声明。代码编译并按预期工作。

我有两个不同的问题:

  1. 标准是否保证我们在此避免动态内存分配?用户Jarod42告诉我,它使用匿名lambda在一个非常相似的setting中,但我不确定f是否同样存在。

  2. 当我有一个非空模板参数包参数bind()时,如何在Args函数中实例化Args?我的代码不会为非空max_execution_time = 600编译。

0 个答案:

没有答案