我正在阅读“用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[]
我对数字1004感到困惑。为什么它不是1000?这本书说:
这个额外的四个字节是 的地方 系统会保留有关的信息 数组,特别是数量 数组中的对象。
但是系统是什么?这是如何完成的?编译器有帮助吗?
答案 0 :(得分:5)
当使用new []时,运行时需要一些方法来记住分配的数组的大小,因此它知道在使用delete []时要释放多少。在你的特定实现中,它的记忆方式是分配保存大小的额外四个字节(它不必以这种方式工作)。
您可以在C++ FAQ。
中详细了解相关信息答案 1 :(得分:2)
此常见问题解答After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?正好回答了这个问题。
答案 2 :(得分:1)
这是一个依赖于编译器的细节。
当调用delete []时,它只传递一个参数 - 指向数组的指针。为了正确运行,它必须知道在恰当数量的对象上执行析构函数的元素数量。所以它必须在某个地方获取这些信息。
典型的方法是new []在数组有效负载之前加上一个额外的size_t来存储元素的数量。因此,分配的空间量将是
sizeof( size_t ) + numberOfElements * sizeof ( ObjectType )
答案 3 :(得分:0)
当使用new分配数组时,在分配的块的开头使用另一个字来保持分配的字节数。
由于C ++数组不保留有关其大小的信息,因此内存管理器必须保留已分配内存大小的标签,当使用delete []时,读取已分配的Byes的数量,然后内存管理器收取该内存量。
这就是为单个变量调用delete []可能是灾难性的原因
并且为数组调用delete会导致内存泄漏。
答案 4 :(得分:0)
内存管理必须保留一些有关内存块大小的信息。如果没有该信息,删除/删除[]将无法正常工作(如果删除,则可能不需要此信息,因为编译器知道要删除的对象的大小)。
如何保存信息以及new / delete的实现细节在哪里。它可能会根据您使用的编译器或内存管理库(例如SmartHeap)而改变。
有时会分配额外的内存来检测编程错误(比如写入已分配内存的边界)。