【发布时间】:2026-02-20 03:00:01
【问题描述】:
我不确定在从非静态数据成员初始化程序中捕获 this 的 lambda 函数初始化 std::function 时可能存在 GCC 错误。这是 C++ 标准允许的还是 UB?
给定以下代码:
#include <functional>
#include <iostream>
template <typename T>
struct A {
T x = 0;
std::function<void(T)> f = [this](T v) { x = v; };
};
int main() {
A<int> a;
a.f(1);
std::cout << a.x << "\n";
}
据我了解,它应该打印1。但是,当使用 GCC 5.4.0 或 GCC 6.2.0 构建时,a.f(1) 会发出分段错误,因为捕获的 this 指针为空。
以下替代方案按我的预期工作:
-
使用构造函数初始化列表:
template <typename T> struct B { B() : f([this](T v) { x = v; }) {} T x = 0; std::function<void(T)> f; }; -
没有模板:
struct C { int x = 0; std::function<void(int)> f = [this](int v) { x = v; }; };
另外,当使用 Clang 3.8.0 构建时,所有三个版本的行为都符合我的预期,这并不意味着它不是 UB。
【问题讨论】:
-
我倾向于 GCC 错误:
this不应该永远为空。 -
@Rakete1111 适用于 MSVS 2015 更新 3。
-
对我来说似乎很奇怪,你甚至可以这样捕捉。
-
@ViktorSehr 为什么会这样?
std::function<void(T)> f = [this](T v) { x = v; };只是f([this](T v) { x = v; })的语法糖 -
与您发现的错误无关的注释:一个危险是
f通过指针捕获this。然后在复制A时复制它。所以A<int> a = A<int>{};可以(在 C++14 或 11 中)有一个a.f()跟随一个悬空指针。 (通常这可能发生在其他情况下)。其次,注意 ODR 违规在这里非常容易(但我认为标准正在努力修补它们),f中存储的对象的类型是什么?包含上述头文件的两个源文件相同还是不同?
标签: c++ c++11 gcc language-lawyer