Lambda:为什么按值捕获值为const,而不是按引用值捕获?

时间:2013-05-26 22:10:28

标签: c++ c++11 lambda const capture

为什么值为值的值为const,而不是按引用对象捕获:

int a;

auto compile_error = [=]()
{
  a = 1;
}
auto compiles_ok = [&]()
{
  a = 1;
}

对我而言,这似乎不合逻辑,但它似乎是标准的?特别是因为对捕获值的不必要修改可能是一个烦人的错误,但是后果仅限于lambda范围的可能性很高,而通过引用捕获的对象的不需要的修改通常会导致更严重的影响。

那么为什么不默认使用const引用?或者至少支持[const&]和[&]?这种设计的原因是什么?

作为解决方法,您可能应该使用由值捕获的std :: cref包装的const引用吗?

3 个答案:

答案 0 :(得分:7)

假设您正在按值捕获指针。指针本身是const,但是对它指向的对象的访问不是。

int i = 0;
int* p = &i;
auto l = [=]{ ++*p; };
l();
std::cout << i << std::endl;  // outputs 1

这个lambda相当于:

struct lambda {
    int* p;
    lambda(int* p_) : p(p_) {}
    void operator()() const { ++*p; }
};

const上的operator()()使用p相当于将其声明为:

int* const p;

引用也会发生类似的事情。引用本身是“const”(在引号中,因为引用不能重新引用),但是引用它引用的对象不是。

答案 1 :(得分:2)

捕获的引用 也是const。或者更确切地说,引用总是隐式地const - 语言中没有语法允许您更改引用所指向的位置。当a = 1;是引用时,a不会更改引用,而是更改引用所引用的内容。

当你谈到“const reference”时,我觉得你很困惑。您正在谈论“引用const int”(const int &)。 “const”指的是引用指向的东西,而不是引用本身。它与指针类似:使用“指向const int的指针”(const int *),指针本身不是const - 您可以根据需要分配给此类型的变量。一个真正的“const指针”将是int *const。在这里,你不能分配这种类型的东西;但你可以修改它指向的int。因此,指针或引用的“const”与它指向的东西的“const”是分开的。您还可以使用“const指向const int的指针”:const int *const

答案 2 :(得分:0)

我的逻辑说明如下:lambdas只是一段代码,带有可选的必需引用。在您需要实际复制某些内容(通常用于内存管理目的,例如复制shared_ptr)的情况下,您仍然不希望lambda具有自己的状态。这是一个非常不寻常的情况。

我认为只有以下2个选项感觉“正确”

  • 使用一些局部变量封闭一些代码,以便您可以“传递”
  • 与上面相同,只是添加了内存管理,因为你可能想要异步执行那段代码,而且创建范围将会消失。

但是当lambda是“可变的”时,即它捕获的值不是const,这意味着它实际上支持它自己的状态。这意味着,每次调用 lambda 时,它都会产生不同的结果,这不是基于其实际的闭包,而是基于其内部状态,这在我的书中有点反直觉,因为lambda起源于函数式语言。

然而,C ++,作为C ++,为你提供了一种绕过这种限制的方法,也让它变得有点丑陋,只是为了确保你知道你做了一些奇怪的事情。

我希望你有这个理由。