通过C ++ 11 lambda中的引用捕获静态变量

时间:2012-12-11 20:19:56

标签: c++ c++11 lambda

主要问题

我正在尝试使用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&lt;的工厂。 T>对象,当您只需要为同一个实例使用重复的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&lt; T>对象可以在静态变量之后被破坏的任何全局对象。

我对此是对的吗?

2 个答案:

答案 0 :(得分:79)

为什么你甚至试图捕获bar?这是静态的。您根本不需要捕获它。只需要捕获自动变量。 Clang会对您的代码产生严重错误,而不仅仅是警告。如果您只是从lambda捕获中删除&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

答案 1 :(得分:11)

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

所以,不,你不能按照标准做到这一点(或者,回答你的第一个问题,这不是有效的C ++ 11而不是编译器错误)

  

5.1.1 / 2 lambda-capture中的名称应在lambda表达式的上下文中,并且应该是this或指向本地   具有自动存储持续时间的变量或引用。

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