C++delete操作符如何找到多态对象的内存位置?

How does the C++ delete operator find the memory location of a polymorphic object?(C++delete操作符如何找到多态对象的内存位置?)

本文介绍了C++delete操作符如何找到多态对象的内存位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道当为DELETE运算符提供的基类指针与对象的实际内存位置不同时,它是如何计算出需要释放的内存位置的。

我想在我自己的自定义分配器/释放分配器中复制此行为。

请考虑以下层次结构:

struct A
{
    unsigned a;
    virtual ~A() { }
};

struct B
{
    unsigned b;
    virtual ~B() { }
};

struct C : public A, public B
{
    unsigned c;
};

我想分配一个C类型的对象,并通过B类型的指针将其删除。据我所知,这是对操作符DELETE的有效使用,它在linux/GCC下工作:

C* c = new C;
B* b = c;

delete b;

有趣的是,由于对象在内存中的布局方式,指针‘b’和‘c’实际上指向不同的地址,并且删除操作符"知道"如何查找和释放正确的内存位置。

我知道,在给定基类指针Find out the size of a polymorphic object的情况下,通常不可能找到多态对象的大小。我怀疑通常也不可能找到对象的真实内存位置。

备注:

  • 我的问题与new[]和delete[]如何工作无关。我对单一对象分配的情况感兴趣。How does delete[] "know" the size of the operand array?。
  • 我也不关心析构函数是如何调用的。我对内存本身的重新分配感兴趣。How 'delete' works when I delete a pointer of base class
  • 我使用-FNO-RTTI和-FNO-EXCEPTIONS进行了测试,因此G++不应该有权访问运行时类型信息。

推荐答案

这显然是特定于实现的。在实践中,实现事情的明智方法相对较少。从概念上讲,这里有几个问题:

  1. 您需要能够获取指向派生最多的对象的指针,即(概念上)包含所有其他类型的对象。

    在标准C++中,可以使用dynamic_cast

    void *derrived = dynamic_cast<void*>(some_ptr);
    

    仅从B*获取C*,例如:

    #include <iostream>
    
    struct A
    {
        unsigned a;
        virtual ~A() { }
    };
    
    struct B
    {
        unsigned b;
        virtual ~B() { }
    };
    
    struct C : public A, public B
    {
        unsigned c;
    };
    
    int main() {
      C* c = new C;
      std::cout << static_cast<void*>(c) << "
    ";
      B* b = c;
      std::cout << static_cast<void*>(b) << "
    ";
      std::cout << dynamic_cast<void*>(b) << "
    ";
    
      delete b;
    }
    

    在我的系统上提供了以下内容

    0x912c008
    0x912c010
    0x912c008
    
  2. 一旦完成,它就成为一个标准的内存分配跟踪问题。这通常通过以下两种方式之一完成,a)记录分配内存之前的分配大小,发现大小只是指针减法,然后b)在某种数据结构中记录分配和空闲内存。有关更多详细信息,请参阅this question,这是一个很好的参考资料。

    使用glibc,您可以相当明智地查询给定分配的大小:

    #include <iostream>
    #include <stdlib.h>
    #include <malloc.h>
    
    int main() {
      char *test = (char*)malloc(50);
      std::cout << malloc_usable_size(test) << "
    ";
    }
    

    该信息同样可用于释放/删除,并用于确定如何处理返回的内存块。

malloc_useable_size的具体实现细节在libc源代码中给出,位于malloc/malloc.c:

(以下包括Colin Plumb稍加编辑的说明)

使用"边界标记"方法维护内存块,如下所示 例如,用Knuth或Stanish描述的。(见保罗·威尔逊的论文 ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps有关此类问题的调查 技术。)空闲块的大小存储在 每一块和最后一块。这使得整合零碎的块成为可能 很快就会变成更大的块。大小字段还保存位 表示区块是空闲还是正在使用。

分配的区块如下所示:

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if allocated            | |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk, in bytes                       |M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
            |             User data starts here...                          .  
            .                                                               .  
            .             (malloc_usable_size() bytes)                      .  
            .                                                               |   
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+     
            |             Size of chunk                                     |  
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  

这篇关于C++delete操作符如何找到多态对象的内存位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:C++delete操作符如何找到多态对象的内存位置?

基础教程推荐