【问题标题】:Behavior of overloaded operator new[] depends on destructor重载运算符 new[] 的行为取决于析构函数
【发布时间】:2018-11-01 05:51:32
【问题描述】:

以下代码 sn -p 重载operator new[] 并打印出size 所需的地址和指针地址

class MyClass
{
private:
    int _data;    //sizeof(MyClass) == 4

public:
    void* operator new[](size_t size)
    {
        cout << "MyClass::operator new[]" << endl;
        cout << "size = " << size << endl;
        void* p = malloc(size);
        cout << "p = " << p << endl;
        return p;
    }
};

int main()
{
    MyClass* a = new MyClass[100];
    cout << "a = " << a << endl;
}

输出

>>  MyClass::operator new[]
>>  size = 400
>>  p = 0x55e335a3f280
>>  a = 0x55e335a3f280

但是,通过显式添加/定义析构函数

class MyClass
{
...
public:
    ...
    ~MyClass() {}
};

int main()
{
    MyClass* a = new MyClass[100];
    cout << "a = " << a << endl;
}

结果变了

>>  MyClass::operator new[]
>>  size = 408
>>  p = 0x564f30cd7280
>>  a = 0x564f30cd7288

意味着表达式new[] 正在向operator new[] 请求额外的8 字节内存。内存的额外字节似乎是存储数组的大小,甚至可以访问!

cout << "info: " << *(reinterpret_cast<size_t*>(a) - 1) << endl;

结果

>>  info: 100

我的问题是谁以及为什么使用这 8 个字节的信息?这是标准的一部分吗?如果是这样,有没有解释为什么它被设计成这样?

【问题讨论】:

  • 请注意,new[] 表达式正在请求额外的 8 个 字节 内存,而不是
  • 糟糕,我会修改帖子。

标签: c++ memory new-operator


【解决方案1】:

当调用任何数组new 时,是否有开销以及有多少开销是unspecified。这种行为完全在编译器的宽容范围之内。额外的空间通常用于指示数组中有多少元素。

在调用delete[]时,需要调用每个元素的析构函数;这只有在我们知道有多少元素的情况下才能做到。在元素具有微不足道的析构函数的情况下,它们都不需要调用,因此不需要空间。

请注意,尽管实现通常在 operator delete 中委托给 std::free,但不能保证,您也应该重载 operator delete

【讨论】:

    【解决方案2】:

    如果您使用非平凡析构函数(例如std::string)而不是析构函数添加成员,您应该会看到类似的行为。

    当你有一个析构函数时,运行时需要知道有多少元素,以便在销毁数组之前销毁它们。

    该标准没有具体说明应该如何实现,但在实际数据之前存储元数据是简单、方便和高效的。

    【讨论】:

      猜你喜欢
      • 2011-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 2011-06-29
      相关资源
      最近更新 更多