删除空指针安全吗?
假设我有以下代码:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
这安全吗? 或者在删除之前必须将 ptr
转换为 char*
?
Suppose I have the following code:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
Is this safe? Or must ptr
be cast to char*
prior to deletion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
C++ 标准未定义通过 void 指针进行删除 - 请参阅第 5.3.5/3 节:
及其脚注:
。
Deleting via a void pointer is undefined by the C++ Standard - see section 5.3.5/3:
And its footnote:
.
这取决于“安全”。 它通常会起作用,因为信息与有关分配本身的指针一起存储,因此释放器可以将其返回到正确的位置。 从这个意义上说,只要您的分配器使用内部边界标记,它就是“安全的”。 (很多人这样做。)
但是,正如其他答案中提到的,删除 void 指针不会调用析构函数,这可能是一个问题。 从这个意义上说,它并不“安全”。
没有充分的理由按照你现在的方式去做你正在做的事情。 如果您想编写自己的释放函数,可以使用函数模板来生成具有正确类型的函数。 这样做的一个很好的理由是生成池分配器,这对于特定类型来说非常有效。
正如其他答案中提到的,这是 C++ 中的 未定义行为。 一般来说,避免未定义的行为是有好处的,尽管主题本身很复杂并且充满了相互冲突的观点。
It depends on "safe." It will usually work because information is stored along with the pointer about the allocation itself, so the deallocator can return it to the right place. In this sense it is "safe" as long as your allocator uses internal boundary tags. (Many do.)
However, as mentioned in other answers, deleting a void pointer will not call destructors, which can be a problem. In that sense, it is not "safe."
There is no good reason to do what you are doing the way you are doing it. If you want to write your own deallocation functions, you can use function templates to generate functions with the correct type. A good reason to do that is to generate pool allocators, which can be extremely efficient for specific types.
As mentioned in other answers, this is undefined behavior in C++. In general it is good to avoid undefined behavior, although the topic itself is complex and filled with conflicting opinions.
这不是一个好主意,也不是您在 C++ 中会做的事情。 您无缘无故地丢失了类型信息。
当您为非基本类型调用析构函数时,不会对数组中要删除的对象调用析构函数。
您应该重写 new/delete。
删除 void* 可能会偶然正确地释放您的内存,但这是错误的,因为结果未定义。
如果出于某种我不知道的原因,您需要将指针存储在 void* 中然后释放它,您应该使用 malloc 和 free。
It's not a good idea and not something you would do in C++. You are losing your type info for no reason.
Your destructor won't be called on the objects in your array that you are deleting when you call it for non primitive types.
You should instead override new/delete.
Deleting the void* will probably free your memory correctly by chance, but it's wrong because the results are undefined.
If for some reason unknown to me you need to store your pointer in a void* then free it, you should use malloc and free.
删除 void 指针是危险的,因为不会在它实际指向的值上调用析构函数。 这可能会导致应用程序中的内存/资源泄漏。
Deleting a void pointer is dangerous because destructors will not be called on the value it actually points to. This can result in memory / resource leaks in your application.
如果您确实必须这样做,为什么不去掉中间人(
new
和delete
运算符)并调用全局operator new
和 <直接代码>运算符删除? (当然,如果您尝试使用new
和delete
运算符,您实际上应该重新实现operator new
和operator
请注意,与
malloc()
不同,operator new
在失败时会抛出std::bad_alloc
(或调用 >new_handler(如果已注册)。If you really must do this, why not cut out the middle man (the
new
anddelete
operators) and call the globaloperator new
andoperator delete
directly? (Of course, if you're trying to instrument thenew
anddelete
operators, you actually ought to reimplementoperator new
andoperator delete
.)Note that unlike
malloc()
,operator new
throwsstd::bad_alloc
on failure (or calls thenew_handler
if one is registered).这个问题没有意义。 您的困惑可能部分是由于人们经常使用
delete
所使用的草率语言:您使用
delete
来销毁动态分配的对象。 这样做,您将形成一个带有指向该对象的指针的删除表达式。 你永远不会“删除指针”。 您真正要做的是“删除由其地址标识的对象”。现在我们明白为什么这个问题没有意义了:空指针不是“对象的地址”。 它只是一个地址,没有任何语义。 它可能来自实际对象的地址,但该信息丢失了,因为它是用原始指针的类型编码的。 恢复对象指针的唯一方法是将 void 指针强制转换回对象指针(这需要作者知道指针的含义)。
void
本身是一个不完整的类型,因此永远不是对象的类型,并且 void 指针永远不能用于标识对象。 (对象由其类型和地址共同标识。)The question makes no sense. Your confusion may be partly due to the sloppy language people often use with
delete
:You use
delete
to destroy an object that was dynamically allocated. Do do so, you form a delete expression with a pointer to that object. You never "delete a pointer". What you really do is "delete an object which is identified by its address".Now we see why the question makes no sense: A void pointer isn't the "address of an object". It's just an address, without any semantics. It may have come from the address of an actual object, but that information is lost, because it was encoded in the type of the original pointer. The only way to restore an object pointer is to cast the void pointer back to an object pointer (which requires the author to know what the pointer means).
void
itself is an incomplete type and thus never the type of an object, and a void pointer can never be used to identify an object. (Objects are identified jointly by their type and their address.)因为 char 没有特殊的析构函数逻辑。 这行不通。
医生不会被叫到。
Because char has no special destructor logic. THIS won't work.
The d'ctor won't get called.
很多人已经评论说不,删除 void 指针是不安全的。 我同意这一点,但我还想补充一点,如果您使用 void 指针来分配连续数组或类似的东西,您可以使用
new
来执行此操作,这样您就可以能够安全地使用delete
(咳咳,需要做一些额外的工作)。 这是通过向内存区域(称为“arena”)分配一个 void 指针,然后将指向 arena 的指针提供给 new 来完成的。 请参阅 C++ 常见问题解答中的此部分。 这是在 C++ 中实现内存池的常见方法。A lot of people have already commented saying that no, it's not safe to delete a void pointer. I agree with that, but I also wanted to add that if you're working with void pointers in order to allocate contiguous arrays or something similar, that you can do this with
new
so that you'll be able to usedelete
safely (with, ahem, a little of extra work). This is done by allocating a void pointer to the memory region (called an 'arena') and then supplying the pointer to the arena to new. See this section in the C++ FAQ. This is a common approach to implementing memory pools in C++.如果你想使用 void*,为什么不只使用 malloc/free 呢? new/delete 不仅仅是内存管理。 基本上,new/delete 调用构造函数/析构函数,并且还有更多事情发生。 如果您只使用内置类型(如 char*)并通过 void* 删除它们,它会起作用,但仍然不建议这样做。 如果您想使用 void*,底线是使用 malloc/free。 否则,您可以使用模板函数以方便起见。
If you want to use void*, why don't you use just malloc/free? new/delete is more than just memory managing. Basically, new/delete calls a constructor/destructor and there are more things going on. If you just use built-in types (like char*) and delete them through void*, it would work but still it's not recommended. The bottom line is use malloc/free if you want to use void*. Otherwise, you can use template functions for your convenience.
几乎没有理由这样做。
首先,如果您不知道数据的类型,并且您只知道它是
void*
,那么您确实应该将该数据视为二进制数据的无类型 blob (unsigned char*
),并使用malloc
/free
来处理它。 有时,对于波形数据等数据是必需的,您需要将void*
指针传递给 C api。 没关系。如果您确实知道数据的类型(即它有一个ctor/dtor),但由于某种原因您最终得到了一个
void*
指针(无论出于何种原因您有)那么您确实应该将其转换回您知道的类型,并对其调用delete
。There is hardly a reason to do this.
First of all, if you don't know the type of the data, and all you know is that it's
void*
, then you really should just be treating that data as a typeless blob of binary data (unsigned char*
), and usemalloc
/free
to deal with it. This is required sometimes for things like waveform data and the like, where you need to pass aroundvoid*
pointers to C apis. That's fine.If you do know the type of the data (ie it has a ctor/dtor), but for some reason you ended up with a
void*
pointer (for whatever reason you have) then you really should cast it back to the type you know it to be, and calldelete
on it.我在我的框架中使用了 void*(又名未知类型),同时进行了代码反射和其他歧义行为,到目前为止,我还没有遇到来自任何编译器的麻烦(内存泄漏、访问冲突等)。 仅因操作不规范而发出警告。
删除未知的 (void*) 是完全有意义的。 只需确保指针遵循以下准则,否则可能会失去意义:
1) 未知指针不得指向具有简单解构函数的类型,因此当转换为未知指针时,永远不应该删除它。 仅在将未知指针强制转换回原始类型后才将其删除。
2) 实例是否在堆栈绑定或堆绑定内存中被引用为未知指针? 如果未知指针引用堆栈上的实例,那么它永远不应该被删除!
3) 您是否 100% 肯定未知指针是有效的内存区域? 不,那么它绝对不应该被删除!
总之,使用未知 (void*) 指针类型可以完成的直接工作非常少。 然而,间接地,当需要数据模糊性时,void* 是 C++ 开发人员可以依赖的重要资产。
I have used void*, (aka unknown types) in my framework for while in code reflection and other feats of ambiguity, and so far, I have had no troubles (memory leak, access violations, etc.) from any compilers. Only warnings due to the operation being non-standard.
It perfectly makes sense to delete an unknown (void*). Just make sure the pointer follows these guidelines, or it may stop making sense:
1) The unknown pointer must not point to a type that has a trivial deconstructor, and so when casted as an unknown pointer it should NEVER BE DELETED. Only delete the unknown pointer AFTER casting it back into the ORIGINAL type.
2) Is the instance being referenced as an unknown pointer in stack bound or heap bound memory? If the unknown pointer references an instance on the stack, then it should NEVER BE DELETED!
3) Are you 100% positive the unknown pointer is a valid memory region? No, then it should NEVER BE DELTED!
In all, there is very little direct work that can be done using an unknown (void*) pointer type. However, indirectly, the void* is a great asset for C++ developers to rely on when data ambiguity is required.
如果您只想要一个缓冲区,请使用 malloc/free。
如果必须使用 new/delete,请考虑一个简单的包装类:
If you just want a buffer, use malloc/free.
If you must use new/delete, consider a trivial wrapper class:
对于 char 的特殊情况。
char 是一种内部类型,没有特殊的析构函数。 因此,关于泄密的争论是没有实际意义的。
sizeof(char) 通常是 1,因此也没有对齐参数。 在 sizeof(char) 不是 1 的罕见平台的情况下,它们会为其 char 分配足够对齐的内存。 因此,对齐论点也是一个没有实际意义的论点。
在这种情况下,malloc/free 会更快。 但是你放弃了 std::bad_alloc 并且必须检查 malloc 的结果。 调用全局 new 和 delete 运算符可能会更好,因为它绕过了中间人。
For the particular case of char.
char is an intrinsic type that does not have a special destructor. So the leaks arguments is a moot one.
sizeof(char) is usually one so there is no alignment argument either. In the case of rare platform where the sizeof(char) is not one, they allocate memory aligned enough for their char. So the alignment argument is also a moot one.
malloc/free would be faster on this case. But you forfeit std::bad_alloc and have to check the result of malloc. Calling the global new and delete operators might be better as it bypass the middle man.