我正在重新阅读前段时间关于 C++ 的一些代码(我现在正在学校学习 Java),我对何时必须使用 delete
感到有些困惑。
例如:声明两个对象时:
Fraction* f1;
Fraction* f2;
并创建 f1
和 f2
像这样:
f1 = new Fraction(user_input1, user_input2);
f2 = new Fraction(user_input3, user_input4);
下次我想用 new
操作符创建一个新对象时,我必须先 delete
吗?我很困惑,因为我习惯于让 Java 中的垃圾收集器处理对象及其删除。在再次使用 new
delete
—?
if (f1) delete f1;
if (f2) delete f2;
// initialize again...
原文由 qnob 发布,翻译遵循 CC BY-SA 4.0 许可协议
与其告诉您何时使用
delete
,我将尝试解释您为什么仍然使用指针。因此,您可以决定何时使用动态对象、如何使用它们以及何时调用delete
(而不是)。经验法则:
delete
需要调用。new
同时写delete
somehwere 在一个合适的位置(并确保它被调用)。new
关键字都 需要 一个delete
关键字。否则,您将占用机器的所有资源,导致应用程序崩溃或停止。它也会使系统变慢。静态创建对象:
动态创建对象:
现在你有了这个地址到堆上的一个内存块。这是一个无效的,因为你没有分配任何东西给它。好的做法是 - 根据您声明它的位置 - 为其分配
NULL
(Windows)或0
(跨平台)。何时使用
delete
一旦您创建了一个动态对象,从而调用了
new
运算符,您就需要在某处调用delete
。在某些情况下,拥有一个
Fraction
数组或指向它的指针可能会很有用。在这里使用int
为简单起见,与跳过错误处理相同:这里发生了一件事,没有通过动态对象分配任何内存。它们会自动释放。函数返回的指针是指向静态内存块的指针。
将
arr
作为指向int
的指针时:现在您必须存储正在泄漏的块,因为您没有清理代码。
当您在每个
Add(...)
delete test
之后调用时,您已经清理了内存,但是您丢失了存储在int* arr[ 10 ]
中的值,因为它们指向保存值的内存。您可以创建另一个函数并在完成这些值后调用它:
小用法示例:
为什么我们要使用指针:
当您调用需要参数(类型)的函数时,您 不是 在传递实例,而是传递它的副本。在上述函数中,您将返回该副本的副本。这将相当于所有涉及的内存的大量重复,并且您使您的应用程序非常慢。
考虑一下:
如果函数需要类型
Test
,则您正在复制int
和 256 个字符。所以制作这个函数,所以它只需要一个指向Test
的指针。然后使用指针指向的内存,不需要复制。在最后一个示例中,我们将 1 添加到
val
的副本中,然后返回该副本。结果: i = 2;
在此示例中,您将地址传递给一个值,然后 - 在取消引用之后 - 将值加一。
结果: i = 2;
现在您已将地址传递给
i
,而不是复制它。在函数中,您直接将 1 添加到该内存块的值。由于您更改了内存本身,因此您什么也没有返回。无效指针/测试有效指针
有时您会遇到以下示例:
这只是为了检查指针
p
是否有效。然而,一个无效的地址——因此不指向你保留的内存(访问冲突)——也会通过。对于您的代码,无效指针是有效地址。因此,要使用这样的检查,您必须使用
NULL
(或0
)指针。当
f1 == 0
时,它不指向任何东西,否则它指向它所指向的任何东西。当您在“主”类中有一个已创建或未创建的指针时,这很有用。
在构造函数中,我们创建了两个指针,因此在析构函数中,我们正在清理这些指针。只检查
ExtendedFeature
因为这个可能会也可能不会被创建。basicFeature
总是被创建。您可以通过调用新函数来替换
if
语句,包括其在析构函数内的范围:removeExtendedFeature()
其中该函数实现为:和新的析构函数:
归零的另一个功能可能是:
我为蹩脚的分数道歉,它具有越来越蹩脚的扩展功能。但作为一个例子,它可以达到目的。