47

主要问题

我正在尝试使用 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< 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< T > 对象设置为任何可能在静态变量之后被破坏的全局对象。

我是对的吗?

4

2 回答 2

101

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

#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
于 2012-12-11T20:24:49.090 回答
13

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

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

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

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

于 2012-12-11T20:38:26.200 回答