2009-11-13 63 views
3

我正在阅读“Thinking in C++”,我对这位新操作员感到困惑。下面是书中的代码:为什么新的[]分配额外的内存?

//: C13:ArrayOperatorNew.cpp 
// Operator new for arrays 

#include <new> // Size_t definition 
#include <fstream> 

using namespace std; 

ofstream trace("ArrayOperatorNew.out"); 

class Widget 
{ 
    enum { sz = 10 }; 
    int i[sz]; 

    public: 

    Widget() { trace << "*"; } 
    ~Widget() { trace << "~"; } 

    void* operator new(size_t sz) 
    { 
     trace << "Widget::new: " 
       << sz << " bytes" << endl; 
     return ::new char[sz]; 
    } 

    void operator delete(void* p) 
    { 
     trace << "Widget::delete" << endl; 
     ::delete []p; 
    } 

    void* operator new[](size_t sz) 
    { 
     trace << "Widget::new[]: " 
       << sz << " bytes" << endl; 
     return ::new char[sz]; 
    } 

    void operator delete[](void* p) 
    { 
     trace << "Widget::delete[]" << endl; 
     ::delete []p; 
    } 
}; 

int main() 
{ 
    trace << "new Widget" << endl; 
    Widget* w = new Widget; 
    trace << "\ndelete Widget" << endl; 
    delete w; 
    trace << "\nnew Widget[25]" << endl; 
    Widget* wa = new Widget[25]; 
    trace << "\ndelete []Widget" << endl; 
    delete []wa; 
} ///:~ 

,这里是在“ArrayOperatorNew.out”

new Widget 
Widget::new: 40 bytes 
* 
delete Widget 
~Widget::delete 
new Widget[25] 
Widget::new[]: 1004 bytes 
************************* 
delete []Widget 
~~~~~~~~~~~~~~~~~~~~~~~~~ 
Widget::delete[] 

跟踪的我感到困惑,为什么它不是1000号1004的内容?书中说:

这额外的四个字节就是 系统保存有 阵列的信息,特别是在阵列中 对象的数量。

但是什么是系统?这是如何完成的?编译器在这里帮助?

回答

5

当使用新的[]运行时需要一些方法来记住分配的数组的大小,因此它知道多少使用delete []时要解除。在你的特定实现中,记住的方式是分配额外的四个字节来保存这个大小(它不必这样工作)。

您可以在C++ FAQ中阅读更多关于此的内容。

1

这是一个依赖于编译器的细节。

当delete []被调用时,它只传递一个参数 - 指向数组的指针。为了正确运行,必须知道在正确数量的对象上执行析构函数的元素数量。所以它必须在某个地方获得这些信息。

典型的方法是new []预先加载一个额外的size_t来存储元素数量。这样的分配空间量会

sizeof(size_t) + numberOfElements * sizeof (ObjectType) 
0

当为new分配一个数组时,在分配块的开头使用一个额外的字来保留分配的字节数。
由于C++数组不保存有关其大小的信息,因此当使用delete []时,内存管理器必须将tab分配给分配内存的大小,读取已分配的数量,然后内存管理器收取内存量。 这就是为什么对单个变量调用delete []会造成灾难性的原因 并且对数组调用delete会导致内存泄漏。

0

内存管理必须保留一些关于内存块大小的信息。如果没有这些信息,delete/delete []不能正常工作(在删除的情况下,这个信息可能不是必须的,sinc编译器知道被删除的对象的大小)。

信息如何保存,以及新/删除的实现细节在哪里。它可能会根据编译器或您使用的内存管理库(例如SmartHeap)而变化。

有时会分配额外的内存来检测编程错误(如在分配的内存边界上写入)。

相关问题