【问题标题】:Segmentation fault for lambda function in non-static data member initializer非静态数据成员初始化程序中 lambda 函数的分段错误
【发布时间】: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&lt;void(T)&gt; f = [this](T v) { x = v; }; 只是 f([this](T v) { x = v; }) 的语法糖
  • 与您发现的错误无关的注释:一个危险是f 通过指针捕获this。然后在复制A 时复制它。所以 A&lt;int&gt; a = A&lt;int&gt;{}; 可以(在 C++14 或 11 中)有一个 a.f() 跟随一个悬空指针。 (通常这可能发生在其他情况下)。其次,注意 ODR 违规在这里非常容易(但我认为标准正在努力修补它们),f 中存储的对象的类型是什么?包含上述头文件的两个源文件相同还是不同?

标签: c++ c++11 gcc language-lawyer


【解决方案1】:

你不能这样做:

template <typename T>
struct A {
    T x = 0;
    std::function<void(T)> f = [this](T v) { x = v; };
};

当您定义f 时,this 不存在。需要在构造函数中初始化f,如:

A(){ f = [this](T v){ x=v; } }

它适用于 G++4.8。

【讨论】:

    【解决方案2】:

    您的代码在 VS2015 (windows) 上编译和运行。 所以这可能是编译器错误。

    此外,如果您要删除模板,它适用于http://cpp.sh/ 试试这个代码:

    #include <functional>
    #include <iostream>
    
    struct A {
          int x = 0;
          std::function<void(int)> f = [this](int v) { x = v; };
    };
    
    int main() {
          A  a;
          a.f(1);
          std::cout << a.x << "\n";
    }
    

    在 cpp.sh 上运行原始代码给出:

     internal compiler error: in tsubst_copy, at cp/pt.c:12569
    Please submit a full bug report
    

    所以我猜这是一个错误

    【讨论】:

    • 某些东西在 VS 上是否有效通常并不能表明该东西的合法性有多大用处...:P 和 cpp.sh 使用 GCC 4.9.2,但是由于您更改了代码,我也不确定这意味着什么。
    • 在 cpp.sh 上运行原始代码给出:7:35: internal compiler error: in tsubst_copy, at cp/pt.c:12569 请提交完整的错误报告,所以我猜这是一个错误