2

以下のコードに何か問題がありますか?

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

ただし、これは非標準であり、危険である可能性があるのではないかと心配しています。

編集:なぜcharあなたが尋ねる配列に初期化するのですか? ブロックが十分に大きいことが判明した場合、ヒープからサイズのブロックを割り当て、sizeof(buffer_type)繰り返し割り当てのために再利用することができます (つまり、メモリ割り当ての繰り返しを避けます)。

void*operator new(std::size_t サイズ);

影響: new-expression (5.3.4) によって呼び出される割り当て関数 (3.7.4.1) は、そのサイズのオブジェクトを表すために適切に整列された size バイトのストレージを割り当てます。

ヒープから割り当てると、アライメントの問題は解消されると思います。

4

3 に答える 3

2

既に述べた配置の問題に加えて、配置によってラムダのコピーを作成してnewいますが、コピーを破棄していません。

次のコードは、問題を示しています。

// This class plays the role of the OP's lambdas
struct Probe {
    Probe() { std::cout << "Ctr" << '\n'; }
    Probe(const Probe&) { std::cout << "Cpy-ctr" << '\n'; }
    ~Probe() { std::cout << "Dtr" << '\n'; }

};

// This plays the role of the OP's assign_lambda
void f(const Probe& p) {

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

    static buffer_type store;
    new (&store) Probe(p);
}

int main() {

    Probe p;

    // This plays the role of the loop
    f(p);
    f(p);
    f(p);
}

出力は次のとおりです。

Ctr
Cpy-ctr
Cpy-ctr
Cpy-ctr
Dtr

したがって、4 つのオブジェクトが構築され、1 つのみが破棄されます。

さらに、OPのコードでstorestatic、これは、ラムダが生のメモリであるかのように、一方のラムダが他方の上に繰り返し構築されることを意味します。

于 2013-07-11T10:57:31.413 に答える