在std :: function捕获中悬空引用。为什么不明确的行为?

时间:2018-03-21 02:06:48

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

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

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

1 个答案:

答案 0 :(得分:3)

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

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

为了防止这种情况发生,除非在当前范围结束之前丢弃lambda和所有副本,否则不要使用任何类型的[&]捕获。

无法确定性地检测C ++上的所有悬空引用。以不会产生99%代码悬挂引用风险的样式编写代码。在1%的情况下,你不能出于任何原因,非常小心,评论很多,并包括没有悬挂参考的证据。

有许多工具可以帮助追踪悬空引用,或多或少,但没有一种工具足以可靠地处理那些坚持做蠢事的程序员。询问工具建议是明确偏离SO的主题。