【问题标题】:Capturing a static variable by reference in a C++11 lambda在 C++11 lambda 中通过引用捕获静态变量
【发布时间】:2023-03-03 02:30:01
【问题描述】:

主要问题

我正在尝试使用 GCC 4.7.2 编译以下代码:

#include <iostream>

int foo() {
    static int bar;
    return [&bar] () { return bar++; } (); // lambda capturing by reference
}

int main (int argc, char* argv[]) {
    std::cout << foo() << std::endl;
    return 0;
}

似乎进展不顺利,因为输出是这个:

$p2.cpp: In function ‘int foo()’:
$p2.cpp:6:14: warning: capture of variable ‘bar’ with non-automatic storage duration [enabled by default]
$p2.cpp:4:16: note: ‘int bar’ declared here

所以,我的第一个问题是:

这是 GCC 的失败,还是代码不是合法的 C++11?最新版本的 GCC 是否已解决此问题?

在 shared_ptr 工厂中使用技巧

我考虑根据这个原理构建一个工件,但使用非文字静态变量。此工件旨在成为 shared_ptr 对象的工厂,当您只需要同一实例的重复 shared_ptr 容器时,它可以避免创建新的 T 对象。

这个工件看起来像:

std::shared_ptr<Foo> create(std::string name) {
    static std::unordered_map<std::string,std::weak_ptr<Foo>> registry;

    if (auto it = registry.find(name) != registry.end())
        return registry[name].lock();

    auto b = std::shared_ptr<Foo>(
        new Foo(name), 
        [&registry] (Foo* p) {
            registry.erase(p->getName());
            delete p;
        });

    registry.emplace(name,b);
    return b;
}

据我所知,如果之前讨论的 GCC 问题在 C++11 一致性方面不是问题,那么这个工件也不应该是问题。使用此 hack 唯一需要注意的是,不要将生成的 shared_ptr 对象设置为任何可能在静态变量之后被破坏的全局对象。

我说得对吗?

【问题讨论】:

  • 在 g++ 4.6.3 上编译并运行良好

标签: c++ c++11 lambda


【解决方案1】:

你为什么还要抓bar?它是静态的。你根本不需要捕捉它。只有自动变量需要捕获。 Clang 会在您的代码上引发严重错误,而不仅仅是警告。如果您只是从 lambda 捕获中删除 &amp;bar,那么代码就可以完美运行。

#include <iostream>

int foo() {
    static int bar;
    return [] () { return bar++; } (); // lambda capturing by reference
}

int main (int argc, char* argv[]) {
    std::cout << foo() << std::endl;
    std::cout << foo() << std::endl;
    std::cout << foo() << std::endl;
    return 0;
}

打印

0
1
2

【讨论】:

  • @Troy:那么可能是 g++ 4.6.3 中的一个错误。
  • 甜心,以为不在这种情况下,谢谢。
  • 我收到与 extern 全局变量相同的警告(未标记为 static)。我需要捕捉它吗?
  • 如果我只想按值捕获条?当我将 bar 放入 [bar] 时,编译器遇到错误
【解决方案2】:

根据标准,您只能捕获具有自动存储持续时间的变量(或 this,被提及为明确可捕获)。

所以,不,您不能按照标准执行此操作(或者,回答您的第一个问题,这不是有效的 C++ 11 并且不是编译器错误)

5.1.1/2 lambda 捕获中的名称应在 lambda 表达式的上下文范围内,并且应为 this 或引用本地 具有自动存储持续时间的变量或引用。

编辑:而且,正如 Kevin 所说,你甚至不需要捕获本地的 static

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 2014-02-21
    相关资源
    最近更新 更多