我有一个小的家庭作业问题。
给出以下代码:
int * p;
p = new int;
*p = 5;
问题是:为什么这样做没用
p = 0;
delete p;
但很有用
delete p;
p = 0;
?
在我看来,两者都没有用。如果删除了对象,则无法分配新值。
在这两种情况下我也得到了一个Segmentation fault
.
为什么它对以下有用:
delete p;
p = 0;
引用 stroustrup 的回答:为什么不将其操作数删除为零?
考虑
delete p; // ... delete p;
如果 ... 部分没有触及 p 那么第二个“删除 p;” 是一个严重的错误,C++ 实现不能有效地保护自己免受(没有异常的预防措施)。由于根据定义删除零指针是无害的,因此一个简单的解决方案是“删除 p;”。做一个“p = 0;” 在它完成任何其他需要之后。但是,C++ 不保证这一点。 一个原因是 delete 的操作数不必是左值。考虑:
delete p+1; delete f(x);
在这里,delete 的实现没有可以分配零的指针。这些例子可能很少见,但它们确实暗示了不可能保证
any pointer to a deleted object is 0.'' A simpler way of bypassing that
rule'' 是有两个指向一个对象的指针:T* p = new T; T* q = p; delete p; delete q; // ouch!
C++ 明确允许删除的实现将左值操作数清零,我曾希望实现能够做到这一点,但这个想法似乎并没有在实现者中流行。 如果您认为将指针归零很重要,请考虑使用销毁函数:
template<class T> inline void destroy(T*& p) { delete p; p = 0; }
考虑这个通过依赖标准库容器、句柄等来最小化显式使用 new 和 delete 的另一个原因。
请注意,将指针作为引用传递(以允许指针归零)具有防止为右值调用 destroy() 的额外好处:
int* f(); int* p; // ... destroy(f()); // error: trying to pass an rvalue by non-const reference destroy(p+1); // error: trying to pass an rvalue by non-const reference
0
回想一下,允许删除。因此,当你这样做时
p = 0;
delete p; // Deleting zero is ignored
你扔掉旧的值p
(从而造成内存泄漏),然后调用delete 0
被忽略。
然而,当你这样做时
delete p;
p = 0;
您首先使用旧值(取消分配int
),然后才将其归零。这是有道理的,因为一旦执行旧值,p
就会变得既无用又危险delete
。
这会将指针设置为 null,然后调用 delete:
p = 0;
delete p;
这就像说
delete 0;
我认为您在想的是它将 p 指向的 int 设置为零,但可以这样做:
*p = 0;
在第一种情况下,您将 POINTER p 的值分配为“0”,而不是 p 指向的 int 的值。这就是为什么它既无用(实际上会导致内存泄漏),并且当您尝试从内存地址“0”删除时会导致段错误。编辑 - 实际上我刚刚了解到段错误不是由“删除 0”引起的,根据标准,它被忽略了,所以是其他原因造成的。
在第二种情况下,您正在释放 p 指向的内存/对象(这应该没问题),然后将指针分配为具有值“0”,这也应该是好的,所以不知道为什么你在那里出现段错误? 就有用性而言,将 free'd 指针设置为 null 或 '0' 值被认为是一种很好的做法,这样您就可以在取消引用它们之前对其进行测试。
p = NULL;
和
p = 0;
在上述情况下,您将值分配给指针而不是它指向的对象。
是一回事。删除函数用于释放动态分配给对象的内存。
当你说
delete p;
p = 0;
这就像说释放分配给指针 p 的内存,然后你说将指针分配给 NULL。哪个是对的。
在另一种情况下,当你这样做时
p = 0;
delete p;
您是说先将指针分配给 NULL 。现在指针 p 没有指向任何有效的动态分配内存。因此,稍后当您说 delete p 时,编译器找不到任何要释放的内存,因此会引发分段错误。