2017-08-15 50 views
0

C++ lambda表达式具有删除的复制分配操作符。我不知道为什么。但是,这个限制可以很容易解决。但我感觉不太好。以下方法会出现什么问题? Live code复制分配相同类型的C++ lambda表达式

template <class T> void assign(T& dest, T&& val) { 
    dest.~T(); 
    new (&dest) T(std::forward<T>(val)); 
} 

auto make_lambda(int i) { 
    return [v=std::make_shared<int>(i)] {std::cout << *v << "\n"; }; 
} 

int main() { 
    auto one = make_lambda(1); 
    assign(one, make_lambda(2)); 
    one(); // prints 2 
} 

有可能是两个原因,我能想到的:

  1. 建设可能会引发和dest主主仍然未初始化和销毁​​稍后。双删除。
  2. 如果某个写得不好的库在析构函数中抛出,析构函数可能会抛出。

施工中的例外情况也可以通过强有力的例外安全保证来解决。考虑assignv2

template <class T> 
void assignv2(T& dest, const T& src) 
{ 
    static std::allocator<T> alloc; 
    static typename std::aligned_storage<sizeof(T), alignof(T)>::type storage; 
    std::memcpy(&storage, &dest, sizeof(T)); 
    try { 
    new (&dest) T(src); 
    } 
    catch(...) { 
    std::memcpy(&dest, &storage, sizeof(T)); 
    throw; 
    } 
    reinterpret_cast<T*>(&storage)->~T(); 
} 
+1

这气味非常UB的。另外:为什么这样做?您可以*写一个具有所需复制语义的类,并在其中放入一个'operator()'。 – Caleth

+0

这个舞蹈的动机是函数的自动记忆。 – Sumant

+4

为什么你需要存储lambda来记忆函数?您只需要存储函数结果。 – rustyx

回答

1

你并不需要能够(拷贝/移动)分配lambda表达式。

class lambda { 
    std::shared_ptr<int> v; 
public: 
    explicit lambda(int i) : v(make_shared(i)) {} 
    void operator()() { std::cout << *v << "\n"; } 
} 

auto make_lambda(int i) { 
    return lambda(i); 
} 

或者,对于memoization的情况下,如果你不改变memoise

template <typename Func> 
auto memoized_recursion(Func func, Cache c = Cache::NO_RECLAIM) 
{ 
    static std::unordered_map<Func, decltype(memoise(func))> functor_map; 

    if(Cache::RECLAIM == c) 
    return functor_map.insert_or_assign(func, memoize(func)).first->second; 
    else 
    return functor_map.insert(func, memoize(func)).first->second; 
} 
+1

在许多(所有?)情况下,Lambdas可以被类替换。但那里的乐趣在哪里? – Sumant

+0

@Sumant让它变得比必要更复杂的乐趣是什么?如果这是你的目标,你可以尝试写入汇编:P – user463035818

+0

@ tobi303同意。我试图了解这里的细微差别。因此这样问。 – Sumant