c++——浅拷贝和深拷贝、浅赋值和深赋值

发布于:2025-07-12 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

一、拷贝构造函数

1.定义

2.按位拷贝

(1)定义

(2)特点

(3)使用场景

二、浅拷贝

1.什么是浅拷贝

2.特点

三、深拷贝(适用于对态资源)

1.什么是深拷贝

2.特点

四、拷贝赋值运算符的深赋值和浅赋值

1.浅赋值

2.深复制

五、总结


一、拷贝构造函数

1.定义

用已有对象来初始化新对象。如果用户没有自定义拷贝构造函数,则系统默认提供一个缺省的拷贝构造函数。

强调:默认的拷贝构造函数是按位拷贝的方式初始化

2.按位拷贝

(1)定义

 是一种对象复制方式,指将一个对象的所有二进制位(bit)原样复制到另一个对象,即逐字节(byte)复制对象在内存中的原始数据。

强调:按位拷贝是编译器默认的拷贝行为,包含默认拷贝构造函数和默认拷贝赋值运算符的实现逻辑。

(2)特点

①不执行任何自定义代码,仅复制内存数据。

②对指针类型,仅复制指针值(地址),不复制指向的内存。

③当对象包含动态资源(比如堆内存)时,会导致多个对象共享同一块内存,调用析构函数后会导致重复释放问题。此时,不合适使用按位拷贝。

(3)使用场景

①对象成员都是基本类型

class Point {
private:
    int x;  // 基本类型,无动态资源
    int y;
public:
    // 编译器生成的默认拷贝构造函数会执行按位拷贝
    Point(int x_, int y_) : x(x_), y(y_) {}
};

int main() {
    Point p1(10, 20);
    Point p2 = p1;  // 按位拷贝:复制x=10和y=20,安全有效
    return 0;
}

②不需要手动释放资源

③对象的指针成员指向全局内存或字符串常量

class ReadOnlyData {
private:
    const char* str;  // 指向字符串常量(全局资源)
public:
    ReadOnlyData(const char* s) : str(s) {}
};

int main() {
    ReadOnlyData d1("hello");
    ReadOnlyData d2 = d1;  // 按位拷贝:d2.str和d1.str指向同一常量,安全
    return 0;
}

注意:字符串常量存放在数据区,无需手动释放。

二、浅拷贝

根据下面的代码找到运行时出现的问题

class MyString
{
private:
	char* str;
public:
	MyString(const char* p = nullptr) :str(nullptr) //构造函数
	{
		if (nullptr != p)  //先判断是否为空
		{
			int len = strlen(p);//计算字符串的长度
			str = new char[len + 1];//使用new申请空间——堆区申请空间 (1)sizeof计算大小 (2)malloc (3)构造 (4)返回地址
			strcpy(str, p);//将p的值拷贝到str中
		}
	}
	~MyString()//析构函数,
	{
		if (nullptr != str)
		{
			delete[] str;
			str = nullptr;
		}

	} 
	void Print() const  //常方法和普通方法都可以进行调用
	{
		if (str != nullptr)
		{
			cout << str << endl;
		}
	}
};
int main()
{
	MyString s1("yhping");
	MyString s2(s1);//系统自动调用默认拷贝构造函数进行初始化
}

存在的问题:(浅拷贝引起的堆区内存问题)

由于用户没有实现拷贝构造函数,系统默认调用自身的拷贝构造函数,调用后,s1和s2指向同一块内存空间,在调用析构函数时,s3先释放资源,此时,当s1调用析构函数时,会因为多次释放同一块空间,造成程序崩溃。

如图所示:

1.什么是浅拷贝

直接复制对象的所有成员变量值,对于指针类型只复制指针值(地址),不复制指针指向的内存。

2.特点

①多个对象共享同一块动态内存。

②析构时可能导致多次释放同一块内存,引发悬空指针内存泄漏

三、深拷贝(适用于对态资源)

对于上述代码的修改就可以使用深拷贝解决!

1.什么是深拷贝

复制对象的所有成员变量值,对于指针类型,会重新分配内存并复制其指向的内容。

2.特点

①每个对象拥有独立的动态资源副本。

②析构时不会相互影响,避免内存问题。

四、拷贝赋值运算符的深赋值和浅赋值

如果用户没有自定义赋值运算符时,则系统默认提供一个赋值运算符的函数。是一种浅赋值的操作,在语义上等价于按位赋值(逐成员赋值对象)。

如图所示:(默认是浅赋值)

1.浅赋值

(1)定义

赋值时仅复制对象的成员变量值,对于指针类型只复制指针值(地址),不复制指针指向的内存。

(2)特点

  • 多个对象共享同一块动态内存。

  • 赋值后,原对象和目标对象的指针指向同一内存地址。

  • 析构时可能导致多次释放同一块内存,引发悬空指针内存泄漏

2.深复制

对于上述代码造成的问题,可以使用户深赋值解决。

(1)定义

赋值时复制对象的所有成员变量值,对于指针类型,会重新分配内存并复制其指向的内容。

(2)特点

  • 每个对象拥有独立的动态资源副本。

  • 赋值后,原对象和目标对象的指针指向不同内存地址,但内容相同。

  • 析构时不会相互影响,避免内存问题。

五、总结

在类型设计中,使用动态内存或使用内核对象时,必须重新实现拷贝构造函数和赋值重载。(深拷贝、深赋值)。


网站公告

今日签到

点亮在社区的每一天
去签到