【问题标题】:C++ lambda function access write violationC++ lambda函数访问写冲突
【发布时间】:2014-04-30 18:26:37
【问题描述】:

我正在学习如何使用 C++ lambda 函数以及 <functional>function 类。我正在尝试解决这个Code Golf 作为练习(挑战是晚餐咖喱)

我有这个功能:

// This creates a function that runs y a number of 
// times equal to x's return value.
function<void()> Curry(function<int()> x, function<void()> y)
{
    return [&]() {
        for (int i = 0; i < x(); i++)
        {
            y();
        }
    };
}

为了测试这一点,我在 main() 中有这段代码:

auto x = [](){ return 8; };
auto y = [](){ cout << "test "; };
auto g = Curry(x, y);

这会在 Functional.h 中抛出 Access violation reading location 0xCCCCCCCC.

然而,当我将 lambda 函数从 Curry() 内部复制粘贴到我的 main 内部时,如下所示:

auto x = [](){ return 8; };
auto y = [](){ cout << "test "; };
auto g = [&]() {
    for (int i = 0; i < x(); i++)
    {
        y();
    }
};

我让代码按预期运行。为什么会这样?

【问题讨论】:

标签: c++ c++11 lambda


【解决方案1】:

你有一些问题。

这里:

  return [&]() {

通过引用捕获。您捕获的任何变量都必须具有超过您自己的生命周期。这意味着在您捕获和使用的变量生命周期结束后,运行 lambda 将成为未定义的行为。当您返回此 lambda 并捕获本地状态时,这似乎很可能发生。 (注意我说的是变量——由于标准中的一个怪癖,[&amp;] 捕获变量而不是变量引用的数据,因此即使通过[&amp;] 捕获&amp; 函数参数也不安全。这可能会在未来的修订版中改变标准的...在 lambda 实现中,这组特定的规则允许进行巧妙的优化(将 [&amp;] lambdas 减少为具有 1 个指针值的状态(!)),但它也引入了 C++ 中唯一的情况对引用变量的引用...)

改成

  return [=]() {

并按值捕获。

甚至:

  return [x,y]() {

明确列出您的捕获。

当使用不超过当前范围的 lambda 时,我使用 [&amp;]。否则,我会通过价值明确地捕获我将要使用的东西,因为在这种情况下生命周期很重要。

下一步:

    for (int i = 0; i < x(); i++)

每次循环迭代运行一次x。看起来很傻!

改为:

    auto max = x();
    for (auto i = max; i > 0; --i)

它运行max 次,如果x 的返回值更改为unsigned int 或其他什么,它会运行。

或者:

    int max = x();
    for (int i = 0; i < max; ++i)

两者都运行一次x,如果x 返回-1,则表现更好。

您也可以使用晦涩的运算符--&gt;

    int count = x();
    while( count --> 0 )

如果你想让你的代码不可读。 ;)

【讨论】:

  • 即使将参数更改为引用(因为对象确实存在足够长的时间)也可能无济于事。更多详情请访问stackoverflow.com/q/21443023/103167
  • @BenVoigt 是的,引用的生命周期不超过范围。引用数据的生命周期确实如此。我想我应该清楚我说的是变量,而不是数据。
  • @Yakk:我不认为这是一个怪癖或可能会改变;它允许一个非常明智的方案,其中通过存储堆栈指针的副本来实现 lambda 引用捕获。所有讨论都在那个链接的问题中。
  • @BenVoigt 是的,我明白了。我仍然可以称其为怪癖,即使它带来了优化机会。
  • 为什么不for (auto i = x(); i &gt; 0; --i) ?似乎不需要额外的冗长
猜你喜欢
  • 2021-02-16
  • 2022-11-03
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 2018-07-07
相关资源
最近更新 更多