C++ 当容器在使用前被破坏/修改时发出警告(通过引用元素或迭代器使用)

C++ warning when container destroyed/modified before its usage (usage via reference to an element or an iterator)

本文关键字:警告 引用 元素 迭代器 修改 C++      更新时间:2023-10-16

我将从我最近遇到的一个问题开始 - 我有一个向量,我采用了它的迭代器,我存储了迭代器(开始,结束),然后容器超出了范围,因此被破坏了。我不记得有任何编译器警告。这是一个艰难的调试,因为只有当我在非常大的数据集上运行它时,我才会出现段错误。有没有办法在使用迭代器时出现编译器错误/警告/容器修改(放大/缩小)/销毁后对容器项的任何引用?我错过了什么吗?我认为它与const限定符同样重要,因为没有人想要引用混乱容器中的项目,对吧?

我被迫回忆起上述情况,因为现在我有另一个家庭作业 - 创建一个特定的容器。我必须返回代理引用,而不是对某个内存位置的引用,因为在分配给代理引用后,容器的一部分必须写入磁盘。但仅供参考,也许并不重要,它同样可以成为这个问题的正常参考。我想将返回代理引用(或任何返回迭代器的方法)的方法标记为"锁定">,这意味着在引用/迭代器的生命周期内的容器将有效地表现为const。(虽然是不同的const,允许修改单个项目,但禁止修改容器,比如宏属性,例如允许在这个"宏常量"对象上返回 operator[] 的非常量引用)

如何在 c++ 中执行此操作?这个概念在其他语言中存在吗?或者可能是为什么它不起作用? 正如我之前所说,我认为这个概念足够普遍,因为首先数据结构是任何程序的构建块,其次是因为没有人想要引用混乱容器中的项目。

有没有办法在使用迭代器时出现编译器错误/警告/容器修改(放大/缩小)/销毁后对容器项目的任何引用?

是的。它称为静态分析器。如果您使用的是 llvm,则 clang 静态分析器可以帮助您在释放内存后找到内存的一些使用情况。其他编译器也有类似的工具。它们还可以告诉您其他有用的事情,例如何时可以在不初始化的情况下使用变量,以及类似性质的事情。

我想将返回代理引用(或任何返回迭代器的方法)的方法标记为"锁定",这意味着在引用/迭代器的生命周期内,容器将有效地表现为常量。 (虽然是不同的常量,允许修改单个项目,但禁止修改容器,比如宏属性,

我不知道有什么方法可以让编译器在容器被修改时给你错误或警告。但是,可以使用信号量或互斥锁锁定对资源的访问。这将阻止其他代码在使用容器时对其进行修改。还可以编写容器修改方法,以便在资源锁定时调用它们时throw异常。

概括一下你的问题,通常最好传递/保留指向实际容器的引用或指针,而不是迭代器,因为迭代器应该被视为短暂的——它们在许多操作中无效(例如插入和删除元素)。

要处理生存期,您可以将std::shared_ptr传递给(或返回)对象,以确保它在程序的另一部分仍在使用时不会被释放。

关于调试,除了@user1118321提到的静态分析之外,您还可以使用地址清理器(对于 clang,编译并与-fsanitize=address链接,在您的情况下,这将终止程序并带有错误AddressSanitizer: heap-use-after-free和关于发生上下文的非常详细的报告。

关于你关于"锁定"的问题,受到关于使用 Rust 的评论的启发@melpomene:你可以通过将对象移动到另一个函数(从而"锁定"它)然后通过返回它来获得类似于在 rust 中借用的语义(使用std::move()个),然后通过返回它将其移回。但是,在被调用的函数返回("返回/解锁")该对象之前,您根本无法使用该对象。