快期末了,c++深、浅拷贝搞清楚了吗?

2021/6/7 22:38:20

本文主要是介绍快期末了,c++深、浅拷贝搞清楚了吗?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

c++中有两种拷贝:深拷贝,浅拷贝

问答

  • 1, 什么时候用到拷贝函数?
    a,一个对象以值传递的方式传入函数体;
    b,一个对象以值传递的方式从函数返回;
    c,一个对象需要通过另外一个对象进行初始化。

  • 2,什么叫深拷贝?什么是浅拷贝?两者异同?
    如果在类中没有显示地申明一个拷贝函数,那么编译器就会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称为浅拷贝;如果一个类拥有资源,当这个类的对象发生复制过程时候,资源重新分配,这个过程就是深拷贝。按此定义,也就是没有重新分配资源的过程就是浅拷贝。深拷贝与浅拷贝的区别就在于深拷贝会在内存中另外申请空间来储存数据,从而也就解决了指针悬挂问题。简而言之,当数据成员中有指针时,必须要用深拷贝。

  • 3,是否应该自定义拷贝函数?深拷贝好还是浅拷贝好?
    自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。如果用浅拷贝,也就是把对象里的值完全复制给另外一个对象,如A=B。这是如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:**当B把内存释放了(如:析构),这是A内的指针就是野指针了,就会出现错误。

对于普通类型的对象来说,他们之间的复制是很简单的,例如:

int a=1024;
int b=a;

而对于类对象其内部结构一般较为复杂,存在各种成员变量。
当用一个已初始化过的自定义类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。

实例说话

或许部分同学还不是到什么是拷贝,下面就来几个实例供大家理解

1,类对象拷贝简单例子(初探)

#include<iostream>
using namespace std;

class CExample{
    private:
        int a;
    public:
        CExample(int b){
            a=b;
        }
        void Show(){
            cout<<a<<endl;
        }
};

int main(){
    CExample A(100);
    CExample B=A;
    B.Show();
    return 0;
}

上面这段代码运行出来的结果是 100 。从结果可以看出,系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
下面这个例子用来说明拷贝构造函数的工作过程:

#include<iostream>
using namespace std;

class CExample{
    private:
        int a;
    public:
        CExample(int b){
            a=b;
        }
        CExample(const CExample& C){
            a=C.a;
        }
        void Show(){
            cout<<a<<endl;
        }
};

int main(){
    CExample A(100);
    CExample B=A;
    B.Show();
    return 0;
}

2,深浅拷贝对比例子(升级)

//浅拷贝就是对象成员的数据之间的简单赋值,比如你设计了一个类而没有提供它的复制构造函数,当用该类的一个对象去给另外一个对象赋值时所执行的过程就是浅拷贝  
#inlcude<iostream>
using namespace std;

class A{
    private:
        int Data;
    public:
        A(int data){
            Data=data;
        }
        A(){
            
        }
};
int main(){
    A A(1024);
    A b;
    b=a;//不仅仅是数据成员间的赋值哦
}

上例的b=a;就是浅拷贝,即浅拷贝是对象数据之间的简单赋值,执行完后,b.Data=5;但当对象中有如:堆、文件、系统资源时,会有什么不同呢? 看下例

#include<iostream>
using namespace std;

class A{
   private:
        int* Data;
        int Size;
    public:
    A(int size){
        Size=size;
        Data=new int[Size]; //设定有一块动态分配的内存
    }
    A(){
        
    }
    A(const A& a){
        Size=a.size;
        Data=new int(Size);
    }   //深拷贝
    ~A(){
        delete[] Data;
    }   //析构释放资源
};

int main(){
    A a(5);
    A b;
    b=a;    //这次就没有问题了
}

再次提醒

1,比如:

b.size=a.size;
b.data=a.data;

这里b的指针data和a的指针指向了堆上的同一块内存,a和b析构时,b先把其data指向的动态分配的内存释放了一次,而后a析构时又将这块别b释放的内存在释放一次。也就是说对同一块动态内存执行力2次释放,故其释放的结果是未定义的,这将导致内存泄漏和程序奔溃。所以要用深拷贝来解决这个问题。

附加一下几个简单名词解释便于理解相关问题:

内存四区:
1,代码区

存放函数体的二进制代码,由操作系统进行管理的

,2,全局区

存放全局变量和静态变量以及常量

3,栈区

由编译器自动分配释放,存放函数的参数值,局部变量等

4,堆区

由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
意义:不同区域存放的数据,赋予不同的生命周期,使我们的编程有了更大的灵活性。



这篇关于快期末了,c++深、浅拷贝搞清楚了吗?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程