lambda仿函数赋值解决方法

use*_*108 2 c++ c++11

下面的代码有什么问题吗?

#include <iostream>

#include <type_traits>

template <typename T>
void assign_lambda(T&& f)
{
  typedef typename std::remove_reference<T>::type functor_type;

  typedef typename std::aligned_storage<sizeof(functor_type),
    std::alignment_of<functor_type>::value>::type buffer_type;

  static char store[sizeof(buffer_type)];

  auto const p(new (store) functor_type(std::forward<T>(f)));

  (*p)();
}

int main()
{
  for (int i(0); i != 5; ++i)
  {
    assign_lambda([i](){ std::cout << i << std::endl; });
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我担心这可能是非标准的和/或危险的.

编辑:为什么要初始化成一个char你问的数组?sizeof(buffer_type)如果块足够大,可以从堆中分配一块大小并重复用于重复分配(即避免重复的内存分配).

void*operator new(std :: size_t size);

效果:由new-expression(5.3.4)调用的分配函数(3.7.4.1),用于分配大小合适的存储字节,以表示该大小的任何对象.

我想如果我从堆中分配对齐问题就会消失.

Arn*_*rtz 5

你必须确保它store具有正确的对齐方式functor_type.除此之外,我没有看到任何有关标准一致性的问题.但是,您可以通过使数组非静态来轻松解决多线程问题,因为sizeof它提供了一个编译时常量.

§5.3.4,14要求对齐:

[注意:当分配函数返回null以外的值时,它必须是指向已保留对象空间的存储块的指针.假设存储块被适当地对准并且具有所请求的大小.[...] - 结束说明]

还有另一段关于对齐的§3.7.4.1,但该段明确地不适用于放置新的(第18.6.1.3,1节).

要使对齐正确,您可以执行以下操作:

template <typename T>
void assign_lambda(T&& f)
{
  typedef typename std::remove_reference<T>::type functor_type;

  //alignas(functor_type) char store[sizeof(functor_type)];
  std::aligned_storage<sizeof(functor_type), 
            std::alignment_of<functor_type>::value>::type store;

  auto const p(new (&store) functor_type(std::forward<T>(f)));

  (*p)();

  //"placement delete"
  p->~functor_type();
}
Run Code Online (Sandbox Code Playgroud)

更新: 上面显示的方法与仅使用普通变量没有区别:

template <typename T>
void assign_lambda(T&& f)
{
  typedef typename std::remove_reference<T>::type functor_type;

  functor_type func{std::forward<T>(f)};

  func();
}
Run Code Online (Sandbox Code Playgroud)

如果它必须是函数内部的静态变量,则需要一个RAII包装器,用于不可分配的仿函数.只是放置 - 新增是不够的,因为仿函数不会被正确销毁,并且它们拥有的资源(例如通过捕获的智能指针)将不会被释放.

template <typename F>
struct RAIIFunctor {
  typedef typename std::remove_reference<F>::type functor_type;

  std::aligned_storage<sizeof(functor_type), 
            std::alignment_of<functor_type>::value>::type store;

  functor_type* f;

  RAIIFunctor() : f{nullptr} {}
  ~RAIIFunctor() { destroy(); }

  template <class T>
  void assign(T&& t) {
    destroy();
    f = new(&store) functor_type {std::forward<T>(t)};
  }

  void destroy() {
    if (f) 
      f->~functor_type();
    f = nullptr;
  }

  void operator() {
    (*f)();
  }
};


template <typename T>
void assign_lambda(T&& f)
{
  static RAIIFunctor<T> func;

  func.assign(std::forward<T>(f));
  func();
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看代码