对象数组是存储在堆栈中还是堆中?

问题描述

在以下代码中:

#include <iostream>
using namespace std ;

class TypeA {
 public:
  int a[10] ;
  TypeA () {
    int i ;
    for ( i = 0; i != 9; i++) {
      a[i] = double(i) ;
    }
  }
  void printval() {
    int i ;
    for ( i = 0; i != 9; i++) {
      cout << a[i] << endl ; 
    }
  }
  ~TypeA() {
    //delete[] a;
    cout << "TypeA destructor called"<<endl;
  }

} ;


int main() {
  TypeA * ptrA = new TypeA() ;
  ptrA->printval();
  delete ptrA ;

  return 0 ;
}

通过new TypeA(),在堆上实例化一个对象,返回一个指针并保存在main()中。我想知道 a[]TypeA 是否存储在堆上?如果是这样,释放它的适当方法是什么?

解决方法

通常,除非您的类包含指针,否则整个对象都包含在一个分配中。因此,您无需执行任何特殊操作即可清除它。

您可以在您之前调用 delete[] 的事物上调用 new[],并且它必须完全与您之前的指针相同给。由于从未直接实例化 a 属性,因此对其调用 delete 是未定义的行为。

new 在概念上的工作方式并不是那么奇特,它只是分配 sizeof(X) 字节并调用该对象的构造函数。 new[] 的不同仅在于它分配 sizeof(X) * N 字节并调用构造函数 N 次。

,

试试这个代码:

#include <iostream>
#include <type_traits>
#include <cassert>
struct A{
    A() {
        std::cout<<"Called A() for "<<std::hex<<this<<'\n';
    }
};

struct B {
    A arr[10];
    B() {
        std::cout<<"Called B() for "<<std::hex<<this<<'\n';
    }
};

int main() {
    B* ptr = new B;
    static_assert(std::is_standard_layout<B>::value); //Sanity check for this example's case
    std::cout<<"Got ptr = "<<std::hex<<ptr<<std::dec<<" + sizeof(B)  = "<<sizeof(B)<<'\n';
    delete ptr;
    return 0;
}

输出为:

Called A() for 0x10d4eb0
Called A() for 0x10d4eb1
Called A() for 0x10d4eb2
Called A() for 0x10d4eb3
Called A() for 0x10d4eb4
Called A() for 0x10d4eb5
Called A() for 0x10d4eb6
Called A() for 0x10d4eb7
Called A() for 0x10d4eb8
Called A() for 0x10d4eb9
Called B() for 0x10d4eb0
Got ptr = 0x10d4eb0 + sizeof(B)  = 10

如果您看到代码和相应的输出,您可以将类型为 ptr 的对象 B 分配在 0x10d4eb0 处的堆上并且它的大小为 10 (对应 10 个字节,每个对象 A 1 个字节)。所以从 0x10d4eb00x10d4eb9 的内存地址都在堆上。而如果你看到A对象的地址,它们都在这个地址范围内。因此,A 的对象确实位于堆内存区域中。

现在谈到如何处理 arr,需要调用 delete/delete[],视情况而定,仅在使用 new 分配的对象上/new[]。由于 arr 不是这种情况,因此不需要对其调用 delete[]