我想知道人们在编码风格方面如何使用C ++ 0x lambdas。最有趣的问题是编写捕获列表时有多彻底。一方面,语言允许明确地列出捕获的变量,并且通过“显式优于隐式规则”,因此有必要进行详尽的列表以清楚地说明意图。 E.g:
int sum;
std::for_each(xs.begin(), xs.end(), [&sum](int x) { sum += x });
另一个论点是,由于ref-captured本地的生命周期不会因为它们被捕获而改变(因此lambda很容易最终引用其生命周期已经结束的本地),因此捕获显式有助于减少这些错误并追踪它们。
另一方面,该语言还故意提供了自动捕获所有引用的本地语言的快捷方式,所以显然它是打算使用的。并且可以声称,对于上面的一个示例,即使使用自动捕获也会非常清楚会发生什么,并且lambda的生命周期不会比周围的范围更长,所以没有理由不使用它:
int sum;
std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });
显然,这不一定是全有或全无,但必须有一些理由来决定何时自动捕获,以及何时明确捕获。有什么想法吗?
同样的另一个问题是何时使用逐个拷贝 - [=]
,以及何时使用按引用捕获 - [&]
。逐个拷贝显然更安全,因为没有生命周期问题,因此有人可能会认为,只要不需要改变捕获的值(或者看到从其他地方对其进行的更改),就应该默认使用它,并捕获 - 在这种情况下,副引用应被视为(可能是过早的)优化,只有在它明显产生影响的情况下才适用。
另一方面,按引用捕获几乎总是更快(特别是因为它通常可以优化到副本,如果后者实际上更快,对于小类型和可内联模板函数,如大多数STL算法)如果lambda永远不会超出其范围(这也是所有STL算法的情况),那么是安全的,因此在这种情况下默认为引用捕获是一种微不足道的无害优化,不会造成伤害。
你有什么想法?
答案 0 :(得分:6)
我从来没有听说过“明确胜过隐性规则”的规则,我不同意。当然,有些情况确实如此,但也有很多情况并非如此。这就是为什么0x毕竟用auto
关键字添加类型推断的原因。 (以及为什么在可能的情况下已经推断出函数模板参数)有很多情况下隐含是优选的。
我还没有真正使用C ++ lambdas(除了探索VC10测试版),但我大部分时间都会使用后者
std::for_each(xs.begin(), xs.end(), [&](int x) { sum += x });
我的理由?为什么不这样做?很方便。有用。而且它更容易维护。当我修改lambda的主体时,我不必更新捕获列表。我为什么要明确一些编译器比我更了解的东西?编译器可以根据实际使用的内容找出捕获列表。
至于参考和价值的捕捉?我会应用与常规功能相同的规则。如果需要引用语义,请通过引用捕获。如果您需要复制语义,请执行此操作。如果其中任何一个会这样做,那么对于小型类型更喜欢值,如果复制是昂贵的则参考。
与设计常规功能时的选择似乎没有什么不同。
我应该阅读lambdas的规范,但这不是显式捕获列表的主要原因,这样你就可以通过值捕获一些变量而通过引用捕获其他变量?
答案 1 :(得分:2)
我最初的直觉是,按值获取提供或多或少与Java的匿名内部类相同,这是已知数量。但是,当您希望封闭范围是可变的时,而不是使用size-size-1技巧,您可以通过引用来捕获。然后,您有责任将lambda的持续时间限制在参考范围内。
在实践中,我同意你的意见,在处理算法时,通过引用捕获应该是默认值,我希望这将是大多数用法。 Java中匿名内部类的常见用途是侦听器。在C ++中可以看到的侦听器风格接口较少,因此需求较少,但仍然存在。在这种情况下,最好严格按价值捕获,以避免出错的机会。将shared_ptr的值捕获成为一个很大的习惯用语吗?
但是,我还没有使用过lambdas,所以我可能错过了很多东西。
答案 2 :(得分:0)
我可以在这里看到新的编码标准规则! ;)
这有点做作,但为了强调明确的“优势”,请考虑以下几点:
void foo (std::vector<int> v, int x1)
{
int sum = 0;
std::for_each (v.begin ()
, v.end ()
, [&](int xl) { sum += x1; }
}
现在,我故意为此选择了可怜的名字等,但这只是为了说明这一点。如果我们使用显式捕获列表,那么上面的代码将无法编译,但目前它将会编译。
在非常严格的环境中(安全至关重要)我可以看到这样的规则是编码标准的一部分。
答案 3 :(得分:0)
我会选择明确的捕获列表,当你想要捕获大量变量时(你可能做错了),你可以使用抓取所有[&]
捕获列表。
我对这个问题的看法是明确的捕获列表是理想的,应该避免使用隐式变体,只有这样才能让人们在实际需要时不必输入大量的代码。
答案 4 :(得分:0)
我正在阅读以下链接以更好地理解C ++ lambda。示例中使用的编码样式非常简洁,我可以遵循: http://uint32t.blogspot.com/2009/05/using-c0x-lambda-to-replace-boost-bind.html