对象数组是存储在栈中还是堆中?
Is an array of an object stored in stack or heap?
在下面的代码中:
#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[]
of TypeA
是否存储在堆上?如果是这样,释放它的合适方法是什么?
通常,除非您的 class 包含指针,否则整个对象都包含在一个分配中。因此,您不需要做任何特别的事情来清除它。
您可以仅对您之前调用过new[]
的事物调用delete[]
,并且必须完全 给你的指针相同。由于 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
如果您看到代码和相应的输出,您可以关联类型 B
的对象 ptr
分配在 0x10d4eb0
的堆上并且它的大小为10(对应10个字节,对象A各1个字节)。所以从0x10d4eb0
到0x10d4eb9
的内存地址都在堆上。而如果你看到A
的对象的地址,都在这个地址范围内。因此,A的对象确实位于堆内存区。
现在介绍如何处理 arr
,需要调用 delete
/delete[]
,视情况而定,仅在使用 [=21 分配的对象上=]/new[]
。由于 arr
不是这种情况,因此不需要对其调用 delete[]
。
在下面的代码中:
#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[]
of TypeA
是否存储在堆上?如果是这样,释放它的合适方法是什么?
通常,除非您的 class 包含指针,否则整个对象都包含在一个分配中。因此,您不需要做任何特别的事情来清除它。
您可以仅对您之前调用过new[]
的事物调用delete[]
,并且必须完全 给你的指针相同。由于 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
如果您看到代码和相应的输出,您可以关联类型 B
的对象 ptr
分配在 0x10d4eb0
的堆上并且它的大小为10(对应10个字节,对象A各1个字节)。所以从0x10d4eb0
到0x10d4eb9
的内存地址都在堆上。而如果你看到A
的对象的地址,都在这个地址范围内。因此,A的对象确实位于堆内存区。
现在介绍如何处理 arr
,需要调用 delete
/delete[]
,视情况而定,仅在使用 [=21 分配的对象上=]/new[]
。由于 arr
不是这种情况,因此不需要对其调用 delete[]
。