假设我有以下代码:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
这样安全吗?或者在删除之前必须将ptr
转换为char*
吗?
假设我有以下代码:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
这样安全吗?或者在删除之前必须将ptr
转换为char*
吗?
通过void指针删除是C++标准未定义的 - 请参见第5.3.5/3节:
在第一种情况(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,并且静态类型应具有虚拟析构函数,否则行为未定义。在第二种情况(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。
以及它的脚注:
这意味着不能使用void*类型的指针删除对象,因为没有void类型的对象。
.
NULL
,对应用程序内存管理有什么影响吗? - artu-hnrq这取决于"安全"。通常情况下,它会起作用,因为指针与分配本身的信息一起存储,所以释放器可以将其返回到正确的位置。在这个意义上,只要您的分配器使用内部边界标记,它就是"安全"的。(许多分配器都是如此。)
然而,正如其他答案中提到的那样,删除void指针不会调用析构函数,这可能是一个问题。在这个意义上,它不是"安全"的。
没有好的理由按照你现在的方式去做你正在做的事情。如果你想编写自己的释放函数,你可以使用函数模板来生成具有正确类型的函数。这样做的好处是可以生成池分配器,对于特定类型来说非常高效。
正如其他答案中提到的那样,在C++中这是未定义行为。一般来说,避免未定义行为是好的,尽管这个主题本身很复杂,充满了相互冲突的观点。
在C++中这不是一个好主意,也不是你会做的事情。你没有理由失去类型信息。
当你对非基本类型调用它时,你删除数组中的对象时,你的析构函数不会被调用。
相反你应该重载new/delete。
删除void*可能会正确释放内存,但是这是错误的,因为结果是未定义的。
如果由于某种我不知道的原因需要将指针存储在void*中然后释放它,那么应该使用malloc和free。
删除空指针是危险的,因为它实际指向的值的析构函数将不会被调用。这可能会导致应用程序中的内存/资源泄漏。
如果你真的必须这样做,为什么不直接调用全局的operator new
和operator delete
,而不是通过new
和delete
运算符来间接实现呢?(当然,如果你正在尝试监测new
和delete
运算符,那么你实际上应该重新实现operator new
和operator 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
)。delete
时语言不严谨:delete
来销毁动态分配的对象,为此,您需要使用指向该对象的指针形成一个delete表达式。你从来不会“删除指针”。你真正做的是“删除通过其地址标识的对象”。void
本身是不完整的类型,因此永远不是对象的类型,void指针不能用于标识对象。(对象由其类型和地址共同标识。)delete void_pointer
。这是未定义的行为。程序员永远不应该调用未定义的行为,即使响应似乎完成了程序员想要完成的工作。 - David Hammenclass foo
{
~foo() { printf("huzza"); }
}
main()
{
foo * myFoo = new foo();
delete ((void*)foo);
}
new
来做到这一点,这样你就能够安全地使用delete
(需要一些额外的工作)。这是通过将一个空指针分配给内存区域(称为“arena”),然后将该指针提供给新的指针来完成的。请参阅C ++ FAQ中的此部分。这是在C++中实现内存池的常见方法。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);
}
如果你只需要一个缓冲区,使用malloc/free。 如果必须使用new/delete,请考虑使用一个简单的包装类:
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;
malloc
和free
即可。这隐含了构造函数/析构函数不会在void*
指针下面的任何东西上被调用(如下面的答案所述)。 - bobobobo