C++ 是否有任何理由在删除之前检查 NULL 指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/615355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any reason to check for a NULL pointer before deleting?
提问by yesraaj
I often see legacy code checking for NULL
before deleting a pointer, similar to,
我经常看到NULL
在删除指针之前检查遗留代码,类似于,
if (NULL != pSomeObject)
{
delete pSomeObject;
pSomeObject = NULL;
}
Is there any reason to checking for a NULL
pointer before deleting it? What is the reason for setting the pointer to NULL
afterwards?
是否有任何理由NULL
在删除指针之前检查指针?将指针设置为afterafter的原因是什么NULL
?
回答by Randolpho
It's perfectly "safe" to delete a null pointer; it effectively amounts to a no-op.
删除空指针是完全“安全的”;它实际上相当于一个空操作。
The reason you might want to check for null before you delete is that trying to delete a null pointer could indicate a bug in your program.
您可能希望在删除之前检查 null 的原因是尝试删除空指针可能表明您的程序中存在错误。
Edit
编辑
NOTE: if you overload the delete operator, it may no longer be "safe" to delete NULL
注意:如果您重载删除运算符,则可能不再“安全”delete NULL
回答by Konrad Rudolph
The C++ standard guarantees that it is legal to use a null pointer in a delete-expression(§8.5.2.5/2). However, it is unspecifiedwhether this will call a deallocation function (operator delete
or operator delete[]
; §8.5.2.5/7, note).
C++ 标准保证在删除表达式中使用空指针是合法的(第 8.5.2.5/2 节)。但是,未指定这是否会调用释放函数(operator delete
或operator delete[]
;第 8.5.2.5/7 节,注释)。
If a default deallocation function (i.e. provided by the standard library) is called with a null pointer, then the call has no effect (§6.6.4.4.2/3).
如果使用空指针调用默认释放函数(即由标准库提供),则调用无效(第 6.6.4.4.2/3 节)。
But it is unspecified what happens if the deallocation function is not provided by the standard library —?i.e. what happens when we overload operator delete
(or operator delete[]
).
但是如果标准库不提供释放函数会发生什么是不确定的——即当我们重载operator delete
(或operator delete[]
)时会发生什么。
A competent programmer would handle null pointers accordingly insidethe deallocation function, rather than before the call, as shown in OP's code.Likewise, setting the pointer to nullptr
/NULL
after the deletion only serves very limited purpose. Some people like to do this in the spirit of defensive programming: it will make program behaviour slightly more predictable in the case of a bug: accessing the pointer after deletion will result in a null pointer access rather than a access to a random memory location. Although both operations are undefined behaviour, the behaviour of a null pointer access is a lot more predictable in practice (it most often results in a direct crash rather than memory corruption). Since memory corruptions are especially hard to debug, resetting deleted pointers aids debugging.
一个有能力的程序员会在释放函数内相应地处理空指针,而不是在调用之前,如 OP 的代码所示。同样,将指针设置为nullptr
/NULL
删除后的用途非常有限。有些人本着防御性编程的精神喜欢这样做:它会使程序行为在出现错误的情况下稍微更可预测:在删除后访问指针将导致空指针访问,而不是访问随机内存位置。虽然这两个操作都是未定义的行为,但空指针访问的行为在实践中更容易预测(它通常会导致直接崩溃而不是内存损坏)。由于内存损坏尤其难以调试,因此重置已删除的指针有助于调试。
— Of course this is treating the symptom rather than the cause (i.e. the bug). You should treat resetting pointers as code smell.Clean, modern C++ code will make memory ownership clear and statically checked (by using smart pointers or equivalent mechanisms), and thus provably avoid this situation.
— 当然,这是治疗症状而不是原因(即错误)。您应该将重置指针视为代码异味。干净的现代 C++ 代码将使内存所有权清晰并进行静态检查(通过使用智能指针或等效机制),从而可以避免这种情况。
Bonus: An explanation of overloaded operator delete
:
奖励:重载的解释operator delete
:
operator delete
is (despite its name) a function that may be overloaded like any other function. This function gets called internally for every call of operator delete
with matching arguments. The same is true for operator new
.
operator delete
是(尽管它的名字)一个可以像任何其他函数一样重载的函数。对于operator delete
具有匹配参数的每次调用,都会在内部调用此函数。对于 也是如此operator new
。
Overloading operator new
(and then also operator delete
) makes sense in some situations when you want to control precisely how memory is allocated. Doing this isn't even very hard, but a few precautions must be made to ensure correct behaviour. Scott Meyers describes this in great detail Effective C++.
当您想要精确控制内存的分配方式时,重载operator new
(然后也是operator delete
)在某些情况下是有意义的。这样做并不难,但必须采取一些预防措施以确保正确的行为。Scott Meyers 非常详细地描述了Effective C++。
For now, let's just say that we want to overload the global version of operator new
for debugging. Before we do this, one short notice about what happens in the following code:
现在,我们只想说我们要重载 的全局版本以operator new
进行调试。在我们这样做之前,请注意以下代码中发生的事情:
klass* pobj = new klass;
// … use pobj.
delete pobj;
What actually happens here? Well the above can be roughly translated to the following code:
这里究竟发生了什么?那么上面的可以大致翻译成下面的代码:
// 1st step: allocate memory
klass* pobj = static_cast<klass*>(operator new(sizeof(klass)));
// 2nd step: construct object in that memory, using placement new:
new (pobj) klass();
// … use pobj.
// 3rd step: call destructor on pobj:
pobj->~klass();
// 4th step: free memory
operator delete(pobj);
Notice step 2 where we call new
with a slightly odd syntax. This is a call to so-called placement new
which takes an address and constructs an object at that address. This operator can be overloaded as well. In this case, it just serves to call the constructor of the class klass
.
注意第 2 步,我们new
用稍微奇怪的语法调用。这是对所谓的放置new
的调用,它获取一个地址并在该地址构造一个对象。这个运算符也可以重载。在这种情况下,它只是用来调用类的构造函数klass
。
Now, without further ado here's the code for an overloaded version of the operators:
现在,不用多说,这里是运算符重载版本的代码:
void* operator new(size_t size) {
// See Effective C++, Item 8 for an explanation.
if (size == 0)
size = 1;
cerr << "Allocating " << size << " bytes of memory:";
while (true) {
void* ret = custom_malloc(size);
if (ret != 0) {
cerr << " @ " << ret << endl;
return ret;
}
// Retrieve and call new handler, if available.
new_handler handler = set_new_handler(0);
set_new_handler(handler);
if (handler == 0)
throw bad_alloc();
else
(*handler)();
}
}
void operator delete(void* p) {
cerr << "Freeing pointer @ " << p << "." << endl;
custom_free(p);
}
This code just uses a custom implementation of malloc
/free
internally, as do most implementations. It also creates a debugging output. Consider the following code:
与大多数实现一样,此代码仅在内部使用malloc
/的自定义free
实现。它还创建调试输出。考虑以下代码:
int main() {
int* pi = new int(42);
cout << *pi << endl;
delete pi;
}
It yielded the following output:
它产生了以下输出:
Allocating 4 bytes of memory: @ 0x100160
42
Freeing pointer @ 0x100160.
Now, this code does something fundamentally different than the standard implementation of operator delete
: It didn't test for null pointers!The compiler doesn't check this so the above code compiles but it may give nasty errors at run-time when you try to delete null pointers.
现在,这段代码做了一些与标准实现根本不同的事情operator delete
:它没有测试空指针!编译器不会检查这一点,因此上面的代码可以编译,但是当您尝试删除空指针时,它可能会在运行时出现严重错误。
However, as I said before, this behaviour is actually unexpected and a library writer shouldtake care to check for null pointers in the operator delete
. This version is much improved:
然而,正如我之前所说,这种行为实际上是出乎意料的,库编写者应该注意检查operator delete
. 这个版本有很大的改进:
void operator delete(void* p) {
if (p == 0) return;
cerr << "Freeing pointer @ " << p << "." << endl;
free(p);
}
In conclusion, although a sloppy implementation of operator delete
may require explicit null checks in the client code, this is non-standard behaviour and should only be tolerated in legacy support (if at all).
总之,虽然 的草率实现operator delete
可能需要在客户端代码中进行显式空值检查,但这是非标准行为,只能在遗留支持中被容忍(如果有的话)。
回答by EvilTeach
Delete checks for NULL internally. Your test is redundent
在内部删除 NULL 检查。您的测试是多余的
回答by Welbog
Deleting null is a no-op. There's no reason to check for null before calling delete.
删除 null 是无操作的。在调用 delete 之前没有理由检查 null。
You might want to check for null for other reasons if the pointer being null carries some additional information you care about.
如果指针为 null 携带一些您关心的附加信息,您可能出于其他原因想要检查 null。
回答by Lingxi
According to C++03 5.3.5/2, it's safe to delete a null pointer. This following is quoted from the standard:
根据 C++03 5.3.5/2,删除空指针是安全的。以下引用自标准:
In either alternative, if the value of the operand of delete is the null pointer the operation has no effect.
在任一替代方案中,如果 delete 的操作数的值是空指针,则操作无效。
回答by Joe
If pSomeObject is NULL, delete won't do anything. So no, you don't have to check for NULL.
如果 pSomeObject 为 NULL,则 delete 不会做任何事情。所以不,你不必检查NULL。
We consider it good practice to assign NULL to the pointer after deleting it if it's at all possible that some knucklehead can attempt to use the pointer. Using a NULL pointer is slightly better than using a pointer to who knows what (the NULL pointer will cause a crash, the pointer to deleted memory may not)
我们认为在删除指针后将 NULL 分配给指针是一种很好的做法,如果某些笨蛋完全有可能尝试使用该指针。使用NULL指针比使用指向谁知道什么的指针稍好(NULL指针会导致崩溃,指向已删除内存的指针可能不会)
回答by VoidPointer
There is no reason to check for NULL prior to delete. Assigning NULL after delete might be necessary if somewhere in the code checks are made whether some object is already allocated by performing a NULL check. An example would be some sort of cached data that is allocated on demand. Whenever you clear out the cache-object you assign NULL to the pointer so the code that allocates the object knows that it needs to perform an allocation.
没有理由在删除之前检查 NULL。如果在代码中的某处通过执行 NULL 检查来检查是否已经分配了某个对象,则可能需要在删除后分配 NULL。一个例子是某种按需分配的缓存数据。每当您清除缓存对象时,您都会将 NULL 分配给指针,以便分配对象的代码知道它需要执行分配。
回答by Joe Pineda
I believe the previous developer coded it "redundantly" to save some milliseconds: It's a good thing to have the pointer be set to NULL upon being deleted, so you could use a line like the following right after deleting the object:
我相信以前的开发人员对其进行了“冗余”编码以节省一些毫秒:在删除时将指针设置为 NULL 是一件好事,因此您可以在删除对象后立即使用如下所示的行:
if(pSomeObject1!=NULL) pSomeObject1=NULL;
But then delete is doing that exact comparison anyway (doing nothing if it's NULL). Why do this twice? You can always assign pSomeObject to NULL after calling delete, regardless of its current value - but this would be slightly redundant if it had that value already.
但是无论如何,delete 都会进行精确的比较(如果它是 NULL,则什么都不做)。为什么要这样做两次?您始终可以在调用 delete 后将 pSomeObject 分配给 NULL,而不管其当前值如何 - 但如果它已经具有该值,这将有点多余。
So my bet is the author of those lines tried to ensure pSomeObject1 would always be NULL after being deleted, without incurring the cost of a potentially unnecessary test and assignation.
所以我敢打赌,这些行的作者试图确保 pSomeObject1 在被删除后始终为 NULL,而不会产生潜在不必要的测试和分配的成本。
回答by Michael Trausch
It depends on what you are doing. Some older implementations of free
, for example, will not be happy if they are passed a NULL
pointer. Some libraries still have this problem. For example, XFree
in the Xlib library says:
这取决于你在做什么。free
例如, 的一些较旧的实现如果传递一个NULL
指针就会不高兴。一些图书馆仍然有这个问题。例如,XFree
在 Xlib 库中说:
DESCRIPTION
The XFree function is a general-purpose Xlib routine that frees the specified data. You must use it to free any objects that were allocated by Xlib, unless an alternate function is explicitly specified for the object. A NULL pointer cannot be passed to this function.
描述
XFree 函数是一个通用 Xlib 例程,用于释放指定的数据。您必须使用它来释放由 Xlib 分配的任何对象,除非为该对象明确指定了替代函数。不能将 NULL 指针传递给此函数。
So consider freeing NULL
pointers as a bug and you'll be safe.
因此,将释放NULL
指针视为一个错误,您将是安全的。
回答by Michael Trausch
As for my observations, deleting a null pointer using delete is safe in unix based machines ike PARISC and itanium. But is quite unsafe for Linux systems as the process would crash then.
至于我的观察,使用 delete 删除空指针在基于 unix 的机器(如 PARISC 和 itanium)中是安全的。但是对于 Linux 系统来说是非常不安全的,因为进程会崩溃。