面试题答案
一键面试- 构造函数:
- 在构造函数中,为动态分配的成员(如指针指向的堆内存)分配内存。确保在分配内存后进行检查,以防止分配失败。
- 例如:
class MyClass {
private:
int* data;
public:
MyClass(int size) {
data = new int[size];
if (!data) {
throw std::bad_alloc();
}
// 初始化数组等操作
for (int i = 0; i < size; ++i) {
data[i] = i;
}
}
};
- 析构函数:
- 在析构函数中,释放动态分配的内存。对于指针类型的成员,使用
delete
(如果是单个对象)或delete[]
(如果是数组)来释放内存。 - 例如:
- 在析构函数中,释放动态分配的内存。对于指针类型的成员,使用
class MyClass {
private:
int* data;
public:
~MyClass() {
delete[] data;
}
};
- 拷贝构造函数:
- 对于常对象类,拷贝构造函数也需要正确管理内存。它应该执行深拷贝,即分配新的内存,并将源对象的数据复制到新分配的内存中。
- 例如:
class MyClass {
private:
int* data;
public:
MyClass(const MyClass& other) {
int size = 10; // 假设这里知道源对象数组大小,实际可能需要更复杂逻辑获取大小
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
};
- 错误场景及解决办法:
- 浅拷贝问题:
- 错误场景:如果拷贝构造函数只是简单地复制指针,而不是分配新的内存并复制数据,就会导致浅拷贝。这样,当两个对象共享同一块内存时,析构函数会尝试释放同一块内存两次,导致未定义行为。
- 浅拷贝问题:
class MyClass {
private:
int* data;
public:
MyClass(int size) {
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = i;
}
}
// 错误的拷贝构造函数(浅拷贝)
MyClass(const MyClass& other) {
data = other.data;
}
~MyClass() {
delete[] data;
}
};
在上述代码中,当MyClass
对象被拷贝时,两个对象的data
指针指向同一块内存。当其中一个对象被销毁时,这块内存被释放,另一个对象的data
指针就变成了野指针。当另一个对象也试图销毁时,就会导致未定义行为。
- 解决办法:实现深拷贝,如上面正确的拷贝构造函数示例,分配新的内存并复制数据。
- 内存分配失败未处理:
- 错误场景:在构造函数中,如果内存分配失败(例如系统内存不足),而没有进行适当处理,可能会导致程序崩溃。
class MyClass {
private:
int* data;
public:
MyClass(int size) {
data = new int[size];
// 未检查内存分配是否成功
for (int i = 0; i < size; ++i) {
data[i] = i;
}
}
~MyClass() {
delete[] data;
}
};
- **解决办法**:在内存分配后检查返回值,如构造函数示例中,在`new`操作后检查`data`是否为`nullptr`,如果是则抛出异常。这样可以确保程序在内存分配失败时能够进行合理的错误处理。