面试题答案
一键面试1. 栈上创建常对象
- 内存分配:当在栈上创建常对象时,编译器会在栈空间为对象分配内存。栈空间由系统自动管理,其分配过程非常迅速。例如,定义
const MyClass obj;
,系统会在栈上为MyClass
类型的对象obj
预留足够的空间,这个空间大小取决于MyClass
类中成员变量的大小和对齐方式等因素。 - 内存释放:当对象的作用域结束时,系统会自动释放栈上为该对象分配的内存。例如,在一个函数内部创建的栈上常对象,当函数执行完毕返回时,对象占用的栈空间会被自动回收,无需手动干预。
2. 堆上创建常对象
- 内存分配:在堆上创建常对象需要使用
new
运算符。例如,const MyClass* ptr = new const MyClass();
。new
运算符首先会在堆上寻找足够大的内存块来存储MyClass
对象,这涉及到堆内存的管理算法(如空闲链表法等)。如果找到合适的内存块,new
会调用MyClass
的构造函数来初始化对象,然后返回指向该对象的指针。 - 内存释放:堆上创建的常对象需要手动使用
delete
运算符来释放内存。例如,delete ptr;
。delete
运算符会首先调用对象的析构函数,然后将对象占用的堆内存归还给堆管理器,以便后续重新分配。如果忘记使用delete
,会导致内存泄漏。
3. 常对象成员变量内存管理机制
- 基本数据类型成员变量:对于常对象中基本数据类型(如
int
、char
、double
等)的成员变量,它们的内存分配和释放与对象本身的内存分配和释放紧密相关。在栈上创建常对象时,基本数据类型成员变量的内存随着对象在栈上分配而分配,随着对象在栈上释放而释放;在堆上创建常对象时,基本数据类型成员变量的内存随着对象在堆上分配而分配,随着对象通过delete
释放而释放。 - 动态分配成员变量:如果常对象包含动态分配的成员变量(例如通过
new
分配的指针成员),那么在对象的析构函数中需要手动释放这些动态分配的内存。即使对象是常量,析构函数依然会在对象销毁时被调用,以确保动态分配的成员变量内存被正确释放,防止内存泄漏。例如,一个MyClass
类中有int* data;
成员变量,在构造函数中通过data = new int[10];
分配内存,那么在析构函数中需要delete[] data;
来释放内存。 - 对象成员变量:如果常对象包含其他类类型的成员变量,这些成员对象的构造和析构会遵循类的构造和析构规则。在常对象构造时,会首先调用成员对象的构造函数进行初始化;在常对象析构时,会首先调用成员对象的析构函数进行清理。无论常对象在栈上还是堆上创建,成员对象的内存管理都遵循其自身类定义的规则。