删除一个空指针是否安全?

假设我有以下代码:

void* my_alloc (size_t size) { return new char [size]; } void my_free (void* ptr) { delete [] ptr; } 

这安全吗? 或者必须将ptrchar*才能删除?

这取决于“安全”。 它通常会工作,因为信息和指针本身一起存储,所以释放器可以将它返回到正确的位置。 从这个意义上讲,只要你的分配器使用内部边界标签,它就是“安全的”。 (很多人做。)

但是,如上所述,删除一个void指针不会调用析构函数,这可能是一个问题。 从这个意义上说,这不是“安全的”。

没有很好的理由去做你正在做的事情。 如果要编写自己的释放函数,可以使用函数模板生成正确types的函数。 这样做的一个很好的理由是生成池分配器,这对于特定types可以是非常有效的。

通过void指针删除是C ++标准定义的 – 请参阅5.3.5 / 3节:

在第一种select(删除对象)中,如果操作数的静态types与其dynamictypes不同,则静态types应该是操作数dynamictypes的基类,静态types应该具有虚拟析构函数或行为未定义。 在第二个select(删除数组)中,如果要删除的对象的dynamictypes与其静态types不同,则行为是不确定的。

其脚注:

这意味着一个对象不能使用void *types的指针来删除,因为没有voidtypes的对象

这不是一个好主意,也不是在C ++中会做的事情。 你没有理由丢失你的types信息。

当您调用非基元types时,您的析构函数将不会被调用到数组中的对象上。

你应该改写新的/删除。

删除void *可能会正确地释放你的内存,但这是错误的,因为结果是不确定的。

如果由于某种原因,我不知道你需要将你的指针存储在一个void *然后释放它,你应该使用malloc和free。

删除一个void指针是很危险的,因为析构函数不会调用它实际指向的值。 这可能会导致应用程序中的内存/资源泄漏。

因为char没有特殊的析构逻辑。 这将无法正常工作。

 class foo { ~foo() { printf("huzza"); } } main() { foo * myFoo = new foo(); delete ((void*)foo); } 

电话不会被叫到。

如果你真的要做到这一点,为什么不切断中间人( newdelete操作符)并直接调用全局operator newoperator delete ? (当然,如果你正在试图对new操作符和delete操作符进行操作,你实际上应该重新实现operator newoperator delete 。)

 void* my_alloc (size_t size) { return ::operator new(size); } void my_free (void* ptr) { ::operator delete(ptr); } 

请注意,与malloc()不同, operator new在失败时抛出std::bad_alloc (或者在注册时调用new_handler )。

很多人已经评论说,不,删除一个空指针是不安全的。 我同意这一点,但我也想补充一点,如果你正在使用void指针来分配连续的数组或类似的东西,那么你可以用new来做到这一点,这样你就可以安全地使用delete ,啊哈,一点额外的工作)。 这是通过分配一个空指针到内存区域(称为“竞技场”),然后将指针提供给新的竞技场来完成的。 请参阅C ++ FAQ中的这一节。 这是在C ++中实现内存池的常用方法。

如果你想使用void *,为什么不使用malloc / free? 新/删除不仅仅是内存pipe理。 基本上,new / delete调用构造函数/析构函数,还有更多的事情正在进行。 如果你只是使用内置types(如char *)并通过void *删除它,它将工作,但仍然不推荐。 如果你想使用void *,底线是使用malloc / free。 否则,您可以使用模板函数为您提供便利。

 template<typename T> T* my_alloc (size_t size) { return new T [size]; } template<typename T> void my_free (T* ptr) { delete [] ptr; } int main(void) { char* pChar = my_alloc<char>(10); my_free(pChar); } 

这个问题没有意义。 您的困惑可能部分是由于人们经常使用的粗俗语言delete

您使用delete来销毁dynamic分配的对象 。 这样做,你可以用一个指向该对象指针来形成一个删除expression式 。 你永远不会“删除一个指针”。 你真正做的是“删除一个由它的地址标识的对象”。

现在我们明白为什么这个问题没有意义:void指针不是“对象的地址”。 这只是一个地址,没有任何语义。 它可能来自实际对象的地址,但是这些信息会丢失,因为它是以原始指针的types编码的。 恢复对象指针的唯一方法是将void指针转换回对象指针(这要求作者知道指针的含义)。 void本身是一个不完整的types,因此永远不是一个对象的types,而且一个void指针永远不能用来标识一个对象。 (对象由其types和地址共同标识)

没有理由这样做。

首先,如果你不知道数据的types ,而你所知道的只是void* ,那么你应该把这些数据当作一个二进制数据( unsigned char* )的无types来处理,然后使用malloc / free处理它。 这对于波形数据之类的东西有时是必需的,在那里你需要传递给C apis的void*指针。 没关系。

如果你知道数据的types(即它有一个ctor / dtor),但由于某种原因,你最终得到一个void*指针(无论出于何种原因), 那么你应该把它转换回你知道的types它是 ,并呼吁delete它。

我在我的框架中使用了void *,(aka未知types),而在代码reflection和其他模糊性方面,到目前为止,我没有任何编译器遇到任何问题(内存泄漏,访问冲突等)。 由于操作不规范,只能发出警告。

删除一个未知的(void *)是完全有意义的。 只要确保指针遵循这些指导方针,或者可能会停止有意义的事情:

1)未知的指针不能指向一个具有微不足道的解构器的types,所以当它作为一个未知的指针被使用时,它不应该被删除。 只有在将其重新转换回ORIGINALtypes之后,才删除未知指针。

2)实例被引用为堆栈绑定或堆绑定内存中的未知指针吗? 如果未知指针引用堆栈上的一个实例,那么它应该永远不会被删除!

3)你是100%正确的未知指针是一个有效的内存区域? 不,那它永远不会被删除!

总而言之,使用未知的(void *)指针types可以完成很less的直接工作。 然而,间接地说,void *是C ++开发人员在需要数据歧义时依赖的重要资产。

如果你只是想要一个缓冲区,使用malloc / free。 如果你必须使用新的/删除,考虑一个简单的包装类:

 template<int size_ > struct size_buffer { char data_[ size_]; operator void*() { return (void*)&data_; } }; typedef sized_buffer<100> OpaqueBuffer; // logical description of your sized buffer OpaqueBuffer* ptr = new OpaqueBuffer(); delete ptr; 

对于char的特定情况。

char是一个没有特殊析构函数的内部types。 所以泄漏的论点是没有意义的。

sizeof(char)通常是一个,所以也没有alignment参数。 在sizeof(char)不是一个的罕见平台的情况下,它们为它们的char分配足够的内存。 所以alignment参数也是没有意义的。

在这种情况下,malloc / free会更快。 但是,你没收std :: bad_alloc,必须检查malloc的结果。 调用全局的new和delete操作符可能会更好,因为它绕过了中间人。