【问题标题】:Dynamically allocated structure and casting动态分配结构和铸造
【发布时间】:2010-04-13 08:53:38
【问题描述】:

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

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; 

现在,当我调用删除操作符时,它释放了多少内存?

sizeof(int) + sizeof(char)  

或者

sizeof(int) + sizeof(char) + sizeof(char) * 0xFF

?

如果这是由于强制转换而导致的第一种情况,有什么办法可以防止这种内存泄漏的发生?

注意:请不要回答“使用C++多态”之类的,我使用这种方法是有原因的。

【问题讨论】:

  • 你可以像类一样声明结构。不用typedef
  • 是的,我知道,只是一个坏习惯 :)

标签: c++ memory-leaks operators


【解决方案1】:

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

【讨论】:

  • 我不这么认为,我刚刚编译了...只是演员表,怎么了?
  • s/非法/未定义行为/;它是格式良好的代码,假设这些 sn-ps 取自适当的上下文。 stackoverflow.com/questions/2046952/…
  • 是的......就像你可以将任何东西投射到void*,然后将void* 投射到任何东西(甚至直接从一件事到另一件事),并不意味着你实际上可以用其他任何东西做任何事情并让它发挥作用。
  • 好的,它编译时没有警告(-Wall),与那个例子相比,它在一个更大的环境中就像一个魅力......也许这是非法的,但老实说......我不在乎,只是想知道记忆的东西,仅此而已。
  • @Simone 因为行为未定义,所以不知道编译后的代码会做什么。对于您的编译器,它似乎可以工作。
【解决方案2】:

它可能(无法保证)在您的机器上正常工作就像delete 的大多数实现一样(释放内存时),指针的类型无关紧要,但地址。因此,它可能会释放分配给 Bar 的内存(在这种情况下)。

但是,将删除视为扩展为:

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

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

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

【讨论】:

    【解决方案3】:

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

    做你想做的事情的唯一合法方法是使用虚拟析构函数从共同基础继承两个结构 - 然后你将有正确定义的行为并且释放分配没有问题。

    但是,如果 operator newoperator delete 没有重载,并且两个结构都具有微不足道的析构函数,它可能在您的实现中正常工作 - 编译器将调用具有一个参数的 ::operator delete() - 块的地址,它将完全释放适量的内存。但是不要指望它 - 您的代码实际上具有未定义的行为。

    【讨论】:

    • 这些结构并不是为了在实际项目中重载运算符,并且每个 [alloc/dealloc]ation 都遵循我对宏施加的严格规则......在评论中解释起来并不容易,无论如何,你的回答似乎是最好的.. ty ^^
    【解决方案4】:

    别担心,要删除的内存量写在分配的内存块头中,因此您的代码不会泄漏任何内容并准确删除已分配的内容。但如果将其分配为数组,则上述内容将不正确。

    【讨论】:

    • 不,OPs 代码包含未定义的行为。它可以做任何事情。
    【解决方案5】:

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

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

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

    【讨论】:

    • 没有 ctors 也没有 dtors ...我正在使用 C 样式转换“模拟”C++ 多态性,但它们只是被转换的结构,没有任何方法。
    【解决方案6】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      相关资源
      最近更新 更多