与其创建智能指针,为什么我们不能修改C++编译器,以便在编译时更好地发现指针问题



如果我们可以设计智能指针来知道何时根据作用域销毁/删除堆内存。为什么我们不能直接设计编译器,在堆内存超出范围时进行标记而不删除呢?

为什么创建智能指针更实用?

我知道这并不是智能指针的唯一原因和好处,但为什么这些改进不能通过更改编译器来实现呢?

谢谢

当您的代码足够复杂时,决定指针是否超出范围可以简化为某种等效的Halting Problem-编译器无法确定的问题。这并不是说这个问题是可以解决的,而是不切实际的,而是一个决定程序是否停止的计算机程序根本不可能存在。

这种减少到暂停问题的一个微不足道的例子是以下伪代码:

Allocate x;
Do arbitrary tasks using x as storage;
Print x;
Deallocate x;
Do other tasks;

CCD_ 1被泄漏;使用x作为存储"执行任意任务";停顿。

如果您加入额外的考虑因素,例如多线程/并发执行,问题会变得更加严重。

正如Nicol Bolas的回答所提出的那样,也有一些方法可以隐藏编译器无法轻松插入的指针,例如通过uintptr_t来回切换指针,也许用一些双目标函数来混淆它。

另一方面,这在运行时要容易得多。垃圾回收是一种相当成熟的技术,可以在Java虚拟机这样的运行时中看到。

此外,还有编译器帮助检测C++中的泄漏和其他内存问题——clang++和和g++包括一个名为ASAN的运行时清理程序,它将在运行时对非法访问和关闭时的泄漏发出警告,尽管它不会在无法访问/不再使用分配但程序尚未终止时发出警告。

我将忽略更广泛的C++问题,即该语言中存在漏洞,可以将指针隐藏在类似非指针的东西中。是的,其中许多都是UB,但有些API基本上需要这些schenanigan。从实际的角度来看,这些事情使得自动GC变得不可能。相反,我们将假设编译器有一种完美的方法来插入指针来实现这一点。因此,我将关注更明显的问题:

向后兼容性和性能。

假设您可以在解决C/C++互操作问题时做到这一点(即:您的C++指针仍然需要与C指针大小相同并存储相同的信息(。即便如此,大多数人在编写代码时也不会期望垃圾回收。你已经编写了几十年的代码来销毁创建后的对象。

那么,一个基于GC的C++会如何处理这样的代码呢?如果它看到一个指向对象的指针比该对象的显式释放要长,那么什么时候应该销毁它?当用户说要执行时,或者当最后一个指针离开时?如果你选择了前一个答案,那么你就没有任何收获,因为你刚刚打破了GC。如果你选择了后者,那么你就违反了与用户的约定,因为用户明确表示";摧毁这个对象并释放这个内存";而你没有。

因此,必须编写一个代码库,期望GC;你不能只是在幕后把它交给他们。

此外,C++的一个常见哲学是";只为你使用的东西付费";。垃圾收集不是免费的。即使是基于生存期作用域的GC也不是免费的,尤其是shared_ptr变体。但你把这个成本强加给每个人,即使他们没有要求也不需要。

没有自动内存管理是C++的一个特性,而不是一个bug。它允许用户自由决定什么是最好的内存管理形式

最新更新