c++ - 防止或检测 "this"在使用过程中被删除

标签 c++ memory stl containers unsafe

我经常看到的一个错误是容器在迭代时被清除。我试图编写一个小示例程序来演示这种情况的发生。需要注意的一件事是,这种情况经常会发生在许多深度函数调用中,因此很难检测到。

注意:这个例子故意展示了一些设计不佳的代码。我正在尝试找到一种解决方案来检测因编写此类代码而引起的错误,而无需仔细检查整个代码库(约 500 个 C++ 单元)

#include <iostream>
#include <string>
#include <vector>

class Bomb;

std::vector<Bomb> bombs;

class Bomb
{
  std::string name;

public:
  Bomb(std::string name)
  {
    this->name = name;
  }

  void touch()
  {
    if(rand() % 100 > 30)
    {
      /* Simulate everything being exploded! */
      bombs.clear();

      /* An error: "this" is no longer valid */
      std::cout << "Crickey! The bomb was set off by " << name << std::endl;
    }
  }
};

int main()
{
  bombs.push_back(Bomb("Freddy"));
  bombs.push_back(Bomb("Charlie"));
  bombs.push_back(Bomb("Teddy"));
  bombs.push_back(Bomb("Trudy"));

  for(size_t i = 0; i < bombs.size(); i++)
  {
    bombs.at(i).touch();
  }

  return 0;
}

任何人都可以提出一种保证这种情况不会发生的方法吗? 我目前检测到这种情况的唯一方法是将全局 newdelete 替换为 mmap/mprotect并在空闲内存访问后检测使用情况。然而,如果 vector 不需要重新分配(即仅删除一些元素或新大小尚未保留大小),则此方法和 Valgrind 有时无法拾取它。理想情况下,我不想克隆大部分 STL 来制作一个在调试/测试期间始终重新分配每个插入/删除的 std::vector 版本。

一种几乎可行的方法是,如果 std::vector 包含 std::weak_ptr,则使用 .lock()> 创建临时引用可防止其在类方法内执行时被删除。但是,这不能与 std::shared_ptr 一起使用,因为您不需要 lock() ,并且对于普通对象也是如此。仅仅为此创建一个弱指针容器是很浪费的。

其他人能想出一种方法来保护我们自己免受这种情况的影响吗?

最佳答案

最简单的方法是使用 Clang MemorySanitizer 运行单元测试链接到. 让一些持续集成的 Linux 盒子在每次推送时自动执行此操作 进入仓库。

MemorySanitizer 具有“销毁后使用检测”(标志 -fsanitize-memory-use-after-dtor + 环境变量 MSAN_OPTIONS=poison_in_dtor=1 ),因此它会破坏执行代码的测试并使您的持续集成变成红色。

如果您既没有单元测试也没有持续集成,那么您也可以使用 MemorySanitizer 手动调试代码,但这与最简单的方法相比是困难的。因此最好开始使用持续集成并编写单元测试。

请注意,析构函数运行后可能存在内存读写但内存尚未释放的合理原因。例如std::variant<std::string,double> 。它让我们可以分配它 std::string然后double因此它的实现可能会破坏 string并重复使用相同的存储 double 。不幸的是,目前过滤掉此类情况是手动工作,但工具正在不断发展。

关于c++ - 防止或检测 "this"在使用过程中被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50838624/

相关文章:

c++ - 在 C++ 中将 char[] 数组转换为 LPCTSTR

c++ - 了解 union 的内存内容

Android - 将文件保存到内部存储器

c++ - STL类的序列化

c++ - 模板类作为STL容器参数

c++ - 互斥保护宏

c++ - 需要帮助将 argv 实现到某些来源

c++ - 如何迭代打印 SET (STL) 中的元素

c++ - 我的char数组数组只保存最后输入的行

Javascript map 取消引用