std::function wrapper that avoids dynamic memory allocation

天大地大妈咪最大 提交于 2019-12-12 03:26:17

问题


Consider the following code:

#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;
}

This code will execute exactly one of Foo::func1(), Foo::func2(), or Bar::func3(), using a copied instance of an object (that has fallen out of scope).

What I'd like to change with this code is to remove the dynamic allocation inside loop(). To this end, I tried making a wrapper around std::function, like so:

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

I then changed the declaration of g from std::function<void()> to my_function<void()> and replaced g = std::bind(x,y) statements with g.bind(x,y) ones inside loop(). The code compiles and works as expected.

I have 2 separate questions:

  1. Does the standard guarantee that we avoid dynamic memory allocation here? User Jarod42 told me that it does in a very similar setting using an anonymous lambda, but I'm not sure if the same holds here with std::bind.

  2. How do I instantiate f inside my bind() function when I have a nonempty template parameter pack argument Args? My code as is won't compile for nonempty Args.

来源:https://stackoverflow.com/questions/34599965/stdfunction-wrapper-that-avoids-dynamic-memory-allocation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!