C++ Lambda到std::函数转换性能

C++ Lambda到std::函数转换性能,c++,c++11,C++,C++11,我想使用lambda函数异步调用引用计数对象上的方法: void RunAsync(const std::function<void()>& f) { /* ... */ } SmartPtr<T> objPtr = ... RunAsync([objPtr] { objPtr->Method(); }); 虽然此后引用的数量会恢复正常,但出于性能原因,我希望避免过多的引用操作。我不确定这些复制操作都是从哪里来的 有什么方法可以通过减少智能指针对象的副本

我想使用lambda函数异步调用引用计数对象上的方法:

void RunAsync(const std::function<void()>& f) { /* ... */ }

SmartPtr<T> objPtr = ...
RunAsync([objPtr] { objPtr->Method(); });
虽然此后引用的数量会恢复正常,但出于性能原因,我希望避免过多的引用操作。我不确定这些复制操作都是从哪里来的

有什么方法可以通过减少智能指针对象的副本来实现这一点


更新:编译器是Visual Studio 2010。

std::function
在编译器对简单情况进行一些严肃的特殊处理之前,可能不会像自定义functor那么快

但是当
move
合适时,引用计数问题是复制的症状。正如其他人在评论中指出的那样,MSVC没有正确实现
move
。您所描述的用法只需要移动,而不需要复制,因此不应触及引用计数


如果可以,请尝试使用GCC编译,看看问题是否消失。

转换为
std::function
应该只移动lambda。如果没有做到这一点,那么可以说
std::function
的实现或规范中存在缺陷。此外,在您上面的代码中,我只能看到原始
c
的两个副本,一个用于创建lambda,另一个用于从中创建
std::function
。我不知道额外的副本是从哪里来的。

为什么不通过引用捕获?如
[&c]{c.CallMe();}和智能指针相同`@Dani:在许多引用计数的智能指针中,算法是原子的,因此需要更多的开销。@Nawaz-Hm,我不确定这是否可行。如果变量仅通过引用捕获,那么当变量超出范围时会发生什么情况?您是否考虑过使用函数模板,以便完全避免使用
std::function
?如果您可以使lambda无captureress(即,如果您可以找到其他方法将
C
导入lambda,例如使用参数),则可以使用函数指针。您使用的是哪种编译器?MSVC2010属性未实现默认移动构造函数,因此您的lambda仅可复制。我怀疑如果您使用move语义手动实现lambda,您将看到您想要的(这是正确的C++11实现的方式)。在GCC中,我也只能得到两个副本(如果我实现了一个移动构造函数,则会得到一个副本)。不幸的是,我无法在GCC中编译整个项目,但我的演示代码在GCC中的行为与预期的一样。因此,如果我理解正确,问题不是lambda表达式,而是
std::function
实现?在将
std::function
std::bind
一起使用时,我似乎遇到了相同(或更糟)的问题。此外,我曾经有一个自定义的functor实现,我想用
std::function
替换它,但它没有显示这种行为。看来我还不能摆脱它。@fschoenm我不使用Windows,但James McNellis在Microsoft工作,所以你可以在评论中试试他的建议。尝试用原始函数指针替换
std::function
,因为lambda函数也会转换为原始函数指针。
#include <functional>

struct C {
    C() {}
    C(const C& c) { ++s_copies; }

    void CallMe() const {}

    static int s_copies;
};

int C::s_copies = 0;

void Apply(const std::function<void()>& fct) { fct(); }

int main() {
    C c;
    std::function<void()> f0 = [c] { c.CallMe(); };
    Apply(f0);
    // s_copies = 4
}