在C++ 中,浅拷贝和深拷贝主要用于对象复制操作。
浅拷贝:
浅拷贝是指在拷贝对象时,对于对象中的指针成员,只是简单地复制指针的值,而不复制指针所指向的内存空间。这意味着两个对象的指针成员会指向同一块内存区域。如果其中一个对象通过指针修改了这块内存中的数据,那么另一个对象也会受到影响,同时,如果当它释放时会调用两次析构函数,而造成程序崩溃或者错误class MyClass { public: int* data; MyClass() { data = new int(10); } // 编译器提供的默认拷贝构造函数是浅拷贝 MyClass(const MyClass& other) { data = other.data; } };
深拷贝:
深拷贝是指在拷贝对象时,对于对象中的指针成员,不仅复制指针的值,还会为指针所指向的内容重新分配内存空间,并将原来内存中的数据复制到新的内存空间中。这样,两个对象的指针成员分别指向不同的内存区域,相互独立。修改其中一个对象的数据不会影响另一个对象。例如:
class MyClass { public: int* data; MyClass() { data = new int(10); } MyClass(const MyClass& other) { data = new int(*other.data); } };
写时拷贝(了解)
写时拷贝(Copy - on - Write,COW)是一种优化策略。
在C++等编程语言的对象拷贝场景中,当多个对象共享同一块资源(如内存数据)时,一开始并不会真正去复制资源。而是只有在某个对象需要修改共享资源时,才会进行实际的资源复制操作。
例如,有一个字符串类,多个对象可能同时指向同一段存储字符串内容的内存。当这些对象只是读取字符串时,可以共享内存。但当一个对象想要修改字符串内容时,就会为这个对象分配新的内存,将原来的内容复制到新内存,然后进行修改,而其他对象仍然指向原来的未修改的内存。
这样做的好处是,在很多情况下可以避免不必要的资源复制开销,提高程序的性能和内存利用率。
那么,为了解决2次析构的情况,这里就使用到一种叫引用计数的方法
引用计数(了解)
引用计数是一种资源管理技术,主要用于跟踪资源(如内存、对象等)被引用的次数。
在智能指针(如C++中的 std::shared_ptr )的应用场景下,引用计数机制发挥了关键作用。当一个 std::shared_ptr 对象被创建并指向一个资源时,引用计数初始化为1。每当有新的 shared_ptr 对象也指向这个相同的资源时,引用计数就会加1。(若引用计数不是1,则进行深拷贝,再进行修改)例如:
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1;
// 此时引用计数为2
std::cout << p1.use_count() << std::endl;
return 0;
}
当一个 shared_ptr 对象销毁或者被重新赋值,指向别的资源时,引用计数就会减1。当引用计数变为0时,表示没有任何 shared_ptr 对象引用这个资源了,此时就会释放该资源。
引用计数的优点是可以方便地实现资源共享,多个对象可以安全地共享同一个资源,只要还有对象在使用该资源,资源就不会被释放。不过它也有缺点,例如存在循环引用的问题。在两个或多个对象相互引用的情况下,可能会导致引用计数无法归零,资源无法正常释放。
最后,到了本次鸡汤环节:
用图片文字来共勉!