假设我有这样的第一个结构:
typedef struct {
int ivalue;
char cvalue;
}
Foo;
还有第二个:
typedef struct {
int ivalue;
char cvalue;
unsigned char some_data_block[0xFF];
}
Bar;
现在让我说我做以下事情:
Foo *pfoo;
Bar *pbar;
pbar = new Bar;
pfoo = (Foo *)pbar;
delete pfoo;
现在,当我调用delete运算符时,它释放了多少内存?
sizeof(int) + sizeof(char)
或者
sizeof(int) + sizeof(char) + sizeof(char) * 0xFF
如果这是由于施法的第一种情况,有没有办法防止这种内存泄漏发生?
注意:请不要回答“使用C ++多态”或类似的问题,我使用这种方法是有原因的。
答案 0 :(得分:9)
释放的内存量未定义 - 您的代码在C ++中是非法的。
答案 1 :(得分:5)
可能(无法保证)在您的计算机上正常工作与大多数delete
的实现一样(释放内存时)指针的类型无关紧要但地址。由于它将可能解除分配给Bar的内存(在这种情况下)。
但是,将delete视为扩展为:
if ( ptr != 0 ){
ptr->~ClassName();
operator delete(ptr);
}
考虑将错误类型传递给delete
的情况。调用错误的析构函数,这不会在编译时导致错误,但可能会在运行时导致出现问题。
考虑new和delete运算符重载的情况......
答案 2 :(得分:1)
不用担心,要删除的内存量写在已分配的内存块标头内,因此您的代码不会泄漏任何内容并删除已分配的内容。但如果您将其分配为数组,则上述情况不会成立。
答案 3 :(得分:1)
这种代码的整个想法只是未定义的行为。不要这样做。如果有人为一个结构重载operator new
和operator delete
而不为另一个结构重载,会发生什么?
执行所需操作的唯一合法方法是使用虚拟析构函数继承comon库中的两个结构 - 然后您将具有正确定义的行为,并且没有解除分配的问题。
但是如果operator new
和operator delete
没有重载并且两个结构都有简单的析构函数,那么它可能只适用于您的实现 - 编译器将调用::operator delete()
具有一个参数 - 地址块的,它将释放恰到好处的内存量。但是不要指望它 - 你的代码实际上有未定义的行为。
答案 4 :(得分:0)
除了语言法之外,您的代码在实践中将做正确的事情并释放整个对象。大多数编译器只会在调用new / delete时调用底层的malloc / free(或类似的)。
但是,如果你在Bar
中有一个非平凡的析构函数,那就很重要了。缺少虚拟析构函数意味着当您通过基类指针删除时,只会调用基类析构函数。
答案 5 :(得分:0)
同意alemjerus - 这不会造成内存泄漏。我的两分钱:sizeof(int)+ sizeof(char)可能不等于sizeof(Foo),因为结构元素填充,所以分配/解除分配的内存块大小是sizeof(Foo)。