【问题标题】:Dangling references in std::function captures. Why undefined behavior?std::function 捕获中的悬空引用。为什么是未定义的行为?
【发布时间】:2018-08-30 00:31:53
【问题描述】:

我有几个 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;
}

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

【问题讨论】:

  • “成功程序”也是UB

标签: c++ reference functional-programming shared-ptr capture


【解决方案1】:

未定义的行为并不意味着段错误,它意味着任何事情。 “它有效”或“格式化硬盘”或“segfault”或“通过电子邮件将您的浏览器历史记录和密码发送给您的所有联系人”。

在这种情况下,堆栈和堆中的垃圾内存恰好像非垃圾一样布局。

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

没有办法确定性地检测 C++ 上的所有悬空引用。以一种不会对 99% 的代码产生悬空引用风险的风格编写代码。在 1% 的情况下,无论出于何种原因,您都无法做到这一点,请格外小心,大量评论,并提供没有悬空引用的证据。

有许多工具可以或多或少地帮助追踪悬空引用,但没有一个工具足以可靠地处理那些坚持做愚蠢事情的程序员。要求工具推荐显然不是 SO 的主题。

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 2013-01-21
    • 2011-10-11
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 2016-09-29
    • 2018-07-26
    • 1970-01-01
    相关资源
    最近更新 更多