面试题答案
一键面试深拷贝、浅拷贝与移动语义的联系与区别
1. 浅拷贝
浅拷贝是指在对象复制时,只复制对象中指针的值,而不复制指针所指向的内存空间。这意味着多个对象的指针指向同一块内存区域。如果其中一个对象释放了这块内存,其他对象的指针就会变成野指针,导致程序出现未定义行为。
2. 深拷贝
深拷贝是指在对象复制时,不仅复制对象中指针的值,还会为指针重新分配内存,并将原指针所指向的内存内容复制到新分配的内存中。这样每个对象都有自己独立的内存区域,避免了野指针问题,但深拷贝的开销较大,因为每次复制都需要重新分配内存并进行数据复制。
3. 移动语义
移动语义是 C++11 引入的新特性,它允许将资源(如动态分配的内存)从一个对象转移到另一个对象,而不是进行传统的深拷贝。这样可以避免不必要的内存分配和数据复制,提高程序性能。移动语义通过 std::move
函数实现,它将左值转换为右值引用,从而触发移动构造函数或移动赋值运算符。
代码示例
#include <iostream>
#include <memory>
class MyString {
private:
char* data;
size_t length;
public:
// 构造函数
MyString(const char* str = nullptr) {
if (str == nullptr) {
length = 0;
data = new char[1];
data[0] = '\0';
} else {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
}
// 析构函数
~MyString() {
delete[] data;
}
// 拷贝构造函数(深拷贝)
MyString(const MyString& other) {
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
// 拷贝赋值运算符(深拷贝)
MyString& operator=(const MyString& other) {
if (this != &other) {
delete[] data;
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
}
return *this;
}
// 移动构造函数
MyString(MyString&& other) noexcept {
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
// 移动赋值运算符
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
return *this;
}
void print() const {
std::cout << data << std::endl;
}
};
int main() {
MyString str1("Hello, World!");
MyString str2 = str1; // 调用拷贝构造函数(深拷贝)
MyString str3 = std::move(str1); // 调用移动构造函数
str2.print();
str3.print();
return 0;
}
在上述代码中:
- 深拷贝:拷贝构造函数和拷贝赋值运算符会为新对象重新分配内存,并复制数据,确保每个对象都有独立的内存。
- 移动语义:移动构造函数和移动赋值运算符将资源从源对象转移到目标对象,源对象被置为空,避免了深拷贝的开销。
通过使用移动语义,在某些场景下(如函数返回临时对象),可以显著提高程序性能,同时保证数据的正确处理。