6

如果我这样做:

// (1.)
int* p = new int;
//...do something
delete p;

// (2.)
class sample
{
public:
sample(){}
~sample(){}
};
sample* pObj = new sample;
//...do something
delete pObj;

那么C++编译器怎么知道后面的对象delete是内置数据类型还是类对象呢?

我的另一个问题是,如果我new指向一个int's 数组的指针,那么delete []编译器如何知道要取消分配的内存块的大小?

4

6 回答 6

4

由于您传递给它的指针的类型,它知道它们之间的区别:传递与分配给它的指针类型不同的指针类型是未定义的行为(除非您可以将指针传递给基类,如果析构函数virtual是课程)。

数组的大小将存储在某处。就像在 C 中你可以 malloc 一定数量的内存,然后释放 - 运行时必须设法知道之前分配的大小。

例如,它可以在分配缓冲区之前存储元素的计数。operator new[]该标准明确允许编译器在数组分配的情况下将不同的请求new大小传递给分配函数(柜台。

于 2010-02-27T15:27:05.520 回答
4
  1. 编译器知道指向对象的类型,因为它知道指针的类型:

    • p是一个int*,因此指向的对象将是一个int
    • pObj是 a sample*,因此指向的对象将是 a sample
  2. 编译器知道您int* p指向的是单个int对象还是数组 ( int[N])。这就是为什么必须记住使用delete[]而不是deletefor 数组。

    要取消分配的内存块的大小,最重要的是要销毁的对象的数量是已知的,因为new[]它们将它们存储在某个地方,并且delete[]知道在哪里检索这些值。C++ FAQ Lite 中的这个问题展示了两种常见的实现技术new[]delete[].

于 2010-02-27T15:32:01.783 回答
1

它没有!

所做delete的只是它调用类型的析构函数,在原始类型的情况下这是“无操作”。然后,它将指针传递给::operator delete(或者如果你愿意,可以是一个重载版本),并且那个操作符返回内存(内存管理器问题)。ie 如果你愿意,你可以很容易地用 C++ 编写你自己的内存管理器,该语言默认提供了一个!

于 2010-02-27T15:27:42.383 回答
1
  1. 编译器知道被删除对象的类型,并为您编写不同的代码以获得正确的结果:
    • delete p 可以调用运行时删除,大小为 int。
    • 删除 pObj 可以先调用 pObj->~sample() ,然后用样本的大小删除
  2. 我认为对于数组,数组的大小有一个隐藏值,因此可能会一次性删除整个数组。
于 2010-02-27T15:30:11.163 回答
1

那么C++编译器怎么知道delete后面的对象是内置数据类型还是类对象呢?

因为在编译时,编译器会跟踪每个对象的类型并植入适当的代码。

我的另一个问题是,如果我新建一个指向 int 数组的指针,然后删除 [],那么编译器如何知道要取消分配的内存块的大小?

它不是。这由运行时系统跟踪。
当您动态分配数组时,运行时库将对象的大小与对象相关联,因此当它删除它时,它知道(通过查找关联的值)大小。

但我猜你想知道它是如何关联的?
这取决于系统并且是一个实现细节。但是一个简单的策略是分配一个额外的 4 个字节,将大小存储在前四个字节中,然后返回一个指向分配的第 4 个字节的指针。当你删除一个指针时,你知道它的大小是指针之前的 4 个字节。注意:我并不是说您的系统正在使用这种技术,但它是一种策略。

于 2010-02-27T15:31:34.657 回答
0

For the first (non-array) part of the question, the answers above indicating that the compiler inserts code to de-allocate the appropriate number of bytes based on the pointer type, don't quite provide a clear answer for me... the delete operator 1) calls a destructor if applicable and then 2) calls the "operator delete()" function... it is operator delete which actually de-allocates. I can see compiler-generated code playing a role in part (1), ie. the destination address of the destructor must be inserted. But in part (2), it is a pre-existing library function handling the de-allocation, so how will it know the size of the data? The global operator delete--which, I believe is used in all cases unless a class-member/overloaded-global version is defined by the programmer--accepts only a void* argument spec'ing the start of the data, so it can't even be passed the data size. I've read things indicating the compiler-generated code idea, as well as things suggesting that the global operator delete for non-arrays simply uses free(), ie. it knows the data size not by the pointer type, but by looking a few bytes before the data itself, where the size will have been stashed by new/malloc. The latter is the only solution that makes sense to me, but maybe someone can enlighten me differently...

于 2010-03-02T02:19:29.930 回答