动态分配结构和铸造

时间:2010-04-13 08:53:38

标签: c++ memory-leaks operators

假设我有这样的第一个结构:

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 ++多态”或类似的问题,我使用这种方法是有原因的。

6 个答案:

答案 0 :(得分:9)

释放的内存量未定义 - 您的代码在C ++中是非法的。

答案 1 :(得分:5)

可能(无法保证)在您的计算机上正常工作与大多数delete的实现一样(释放内存时)指针的类型无关紧要但地址。由于它将可能解除分配给Bar的内存(在这种情况下)。

但是,将delete视为扩展为:

if ( ptr != 0 ){
    ptr->~ClassName();
    operator delete(ptr);
}

考虑将错误类型传递给delete的情况。调用错误的析构函数,这不会在编译时导致错误,但可能会在运行时导致出现问题。

考虑new和delete运算符重载的情况......

答案 2 :(得分:1)

不用担心,要删除的内存量写在已分配的内存块标头内,因此您的代码不会泄漏任何内容并删除已分配的内容。但如果您将其分配为数组,则上述情况不会成立。

答案 3 :(得分:1)

这种代码的整个想法只是未定义的行为。不要这样做。如果有人为一个结构重载operator newoperator delete而不为另一个结构重载,会发生什么?

执行所需操作的唯一合法方法是使用虚拟析构函数继承comon库中的两个结构 - 然后您将具有正确定义的行为,并且没有解除分配的问题。

但是如果operator newoperator delete没有重载并且两个结构都有简单的析构函数,那么它可能只适用于您的实现 - 编译器将调用::operator delete()具有一个参数 - 地址块的,它将释放恰到好处的内存量。但是不要指望它 - 你的代码实际上有未定义的行为。

答案 4 :(得分:0)

除了语言法之外,您的代码在实践中将做正确的事情并释放整个对象。大多数编译器只会在调用new / delete时调用底层的malloc / free(或类似的)。

但是,如果你在Bar中有一个非平凡的析构函数,那就很重要了。缺少虚拟析构函数意味着当您通过基类指针删除时,只会调用基类析构函数。

IIRC,未能调用派生的析构函数是上述代码的唯一警告。除此之外,我相信它是有效的代码。 (这些天我的C ++生锈了,所以我可能会偏离标记。)

答案 5 :(得分:0)

同意alemjerus - 这不会造成内存泄漏。我的两分钱:sizeof(int)+ sizeof(char)可能不等于sizeof(Foo),因为结构元素填充,所以分配/解除分配的内存块大小是sizeof(Foo)。