【发布时间】:2011-11-28 16:16:13
【问题描述】:
我想使用 lambda 函数异步调用引用计数对象上的方法:
void RunAsync(const std::function<void()>& f) { /* ... */ }
SmartPtr<T> objPtr = ...
RunAsync([objPtr] { objPtr->Method(); });
创建 lambda 表达式显然会创建一个副本,但我现在遇到的问题是将 lambda 表达式转换为 std::function 对象也会创建一堆我的智能指针的副本,并且每个副本都会增加引用计数。
以下代码应演示此行为:
#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
}
虽然之后引用量恢复正常,但出于性能原因,我想防止过多的引用操作。我不确定所有这些复制操作来自哪里。
有没有什么方法可以通过减少我的智能指针对象的副本来实现这一点?
更新:编译器是 Visual Studio 2010。
【问题讨论】:
-
为什么不通过引用捕获?如
[&c] { c.CallMe(); };和智能指针一样。 ` -
@Dani:在许多引用计数的智能指针中,算法是原子的,因此需要更多的开销。
-
@Nawaz 嗯,我不确定这是否可能。如果仅通过引用捕获变量超出范围时会发生什么?
-
您是否考虑过使用函数模板以便完全避开
std::function?如果您可以使您的 lambda 无捕获(即,如果您可以找到其他方法将C放入 lambda,例如通过使用参数),您可以使用函数指针。 -
您使用的是哪个编译器? MSVC2010 没有属性实现默认移动构造函数,因此您的 lambda 只能复制。我怀疑如果您使用移动语义手动实现 lambda,您会看到您想要的(这就是 C++11 的正确实现方式)。