std::function 捕获中的悬空引用。为什么是未定义的行为?

Dangling references in std::function captures. Why undefined behavior?

我有几个都使用函数捕获的 C++ 程序。其中一个成功,退出代码为 0,但另一个导致 Segmentation fault 错误。 std::shared_ptr<std::string>() 是通过引用捕获的,应该在调用 lambda 之前销毁。如果是这样,那为什么我的第一个程序成功了,而第二个程序却没有呢?

成功的计划

#include <string>
#include <memory>
#include <iostream>
#include <functional>

std::function<void()> lambda;

void assign_closure() {
  std::shared_ptr<std::string> ptr = std::make_shared<std::string>("nope");
  lambda = [&ptr]() {
    std::cout << "Trying to print this should segault: " << *ptr << std::endl;
  };
}

int main(int, char*[]) {
  assign_closure();
  lambda();
  return 0;
}

程序失败

#include <string>
#include <memory>
#include <iostream>
#include <functional>

std::function<void()> lambda;

void assign_closure() {
  std::shared_ptr<std::string> ptr = std::make_shared<std::string>("nope");
  lambda = [&ptr]() {
    std::cout << "Trying to print this should segault: " << *ptr << std::endl;
  };
}

void do_some_work() {
  std::cout << "doing some work" << std::endl;
}

int main(int, char*[]) {
  assign_closure();
  do_some_work();
  lambda();
  return 0;
}

是否有我可以用来发现悬空引用的编译器标志?

未定义的行为并不意味着段错误,它意味着任何东西。 "It works" 或 "format harddrive" 或 "segfault" 或 "email your browser history and passwords to all of your contacts"。

在这种情况下,堆栈和堆中的垃圾内存恰好被布置成non-garbage。

为防止这种情况,请勿使用任何类型的 [&] 捕获,除非 lambda 和所有副本在当前作用域结束前被丢弃。

无法确定地检测 C++ 上的所有悬挂引用。以不会为 99% 的代码产生悬空引用风险的方式编写代码。在 1% 中,无论出于何种原因,你都不能,要非常小心,大量评论,并包括没有悬空引用的证据。

有许多工具可以或多或少地帮助追踪悬空引用,但是 none 足够可靠,可以应对坚持做蠢事的程序员。在 SO 上询问工具推荐显然是题外话。