深拷贝 浅拷贝 以及赋值运算符= 的重载

在一些程序当中,需要将一个对象里的值直接传递给另一个对象,需要进行对象的拷贝。但是在某些情况下也会出现错误,如类内部成员需要动态开辟内存,实行位拷贝,就是将一个对象的值完全复制给另一个对象,如A=B,但如果B中也有一个指针申请了内存,那么A中的成员变量也指向了同一块内存,如果当释放资源的时候,就会导致野指针的出现,出现错误。

深拷贝的简单理解 就是在复制对象内容的过程中,需要重新分配资源,而浅拷贝则是不要重新分配资源。但是浅拷贝存在着问题:当资源释放时会产生资源归属不清的问题,导致运行错误。

当自己书写拷贝函数的时候,类中本身默认的拷贝函数已经不存在,此时需要在拷贝函数处理所需处理的所有数据。

拷贝和赋值:

当对象在声明的时候即用另一个对像进行初始化 即称为拷贝。如果是在声明之后,在进行赋值操作,则需要重载赋值操作符。

结合代码:

#include <iostream>
#include <cstring>
using namespace std;

class A{
    private:
        char* data;
    public:
        A(){}
        A(char* num){
            int len = strlen(num)+1;
            data = new char[len];
            strcpy(data,num);
            cout<<data<<endl;
        }

        ~A(){
            delete[] data;
        }

        void show(){
            cout<<data<<endl;
        }
};

int main(){
    A a("hahah");
    A b;
    b = a;
    b.show();
    A c(a);
    c.show();
    return 0;
}

默认在缺省状态下的赋值操作符 执行 b=a 内存分析:

A,B 指向了同一个内存地址,此时不会出现问题,但是在析构的同时,会出现俩个指针同时释放相同的内存地址,则会出现错误。

需要通过重载赋值运算符进行处理:

#include <iostream>
#include <cstring>
using namespace std;

class A{
    private:
        char* data;

    public:
        A(){}
        A(char* num){
            int len = strlen(num)+1;
            data = new char[len];
            strcpy(data,num);
            cout<<data<<endl;
        }

        //浅拷贝
        //      A(const A& o):data(o.data){}

        //拷贝构造函数  深拷贝
       A(const A& o){
           int len = strlen(o.data)+1;
           data = new char[len];
           if(data!=NULL)
                strcpy(data,o.data);
        }

        //赋值运算符的重载

        A& operator=(const A& o){
            if(this == &o)
                return *this;
            delete[] data;
            data = NULL;

            data = new char[strlen(o.data)+1];
            strcpy(data,o.data);
            return *this;
        }

        ~A(){
            delete[] data;
        }

        void show(){
            cout<<data<<endl;
        }
};

int main(){
    A a("hahah");
    A b;
    b = a;
    b.show();
    A c(a);
    c.show();
    return 0;
}

需要的内存分析应该是这样的:

注:

1.不要在调用构造函数时向其传递对象,应该传递对象的引用。因为传递对象的时候,还是需要调用构造函数,之后向其传入的还是对象,又再一次的调用构造函数,...,如此循环继续下去,导致段错误(栈溢出)。

2.在进行拷贝构函数的时候 函数不需要返回值,但是在进行赋值操作符的时候,需要有返回值,void类型,类的本身,或者是类的引用。

然而 返回是void的时候,不支持链式的赋值即: a=b=c=d...

返回类型的是类的本身

A operator=(const A& o){
            if(this == &o)
                return *this;
            delete[] data;
            data = NULL;

            data = new char[strlen(o.data)+1];
            strcpy(data,o.data);
            return *this;
        }

具体步骤是:

(1)释放元内存资源

(2)申请一块新的内存空间

(3)原堆内存的值赋值到新的内存

(4)创建临时对象(调用拷贝构造函数),返回临时对象

(5)临时对像结束,调用析构函数,释放对象内存

返回类型如果是对象的引用:

A& operator=(const A& o){
            if(this == &o)
                return *this;
            delete[] data;
            data = NULL;

            data = new char[strlen(o.data)+1];
            strcpy(data,o.data);
            return *this;
        }

具体步骤:

(1)释放原内存资源

(2)申请新的内存资源

(3)原值赋值到新的内存

(4)结束

返回对象的引用 不需要调用拷贝构造函数,提高效率,建议采纳。

深拷贝 浅拷贝 以及赋值运算符= 的重载,布布扣,bubuko.com

时间: 2024-10-10 20:41:49

深拷贝 浅拷贝 以及赋值运算符= 的重载的相关文章

深拷贝&浅拷贝

STRING.h文件 #pragma once #include<string.h> class String { public: String(char* str="")      //深拷贝 :_str(new char[strlen(str)+1]) { strcpy(_str, str); cout << "构造函数 " << endl; } ~String() { if (_str!=NULL) { delete[]_s

赋值运算符的重载

赋值运算符两边的类型可以不匹配,需要重载赋值运算符‘=’.赋值运算符只能重载为成员函数. 重载赋值运算符的意义----浅复制和深复制 S1=S2; 浅复制/浅拷贝 执行逐个字节的复制工作 深复制/深拷贝 将一个对象中指针变量指向的内容复制到另一个对象中指针成员对象指向的地方. 对operator=返回值类型的讨论. void不可以,例如a=b=c; 运算符重载时,好的风格 ---尽量保留运算符原本的特性 例如(a=b)=c;//会修改相应a的值,因此使用String &更为合理. #includ

探讨一下iOS中深拷贝&amp;浅拷贝&amp;copy的那些事儿

什么是深拷贝?什么是浅拷贝? 为什么经常看到字符串属性要这样定义,那个copy是神马意思? @property(nonatomic,copy)NSString* name; 为什么下面的写法是错误的? @property(nonatomic,copy)NSMutableString* name; copyWithZone方法又到底是干嘛用的? 接下来,我们将一起,一步一步的去揭晓问题的答案. Copy到底是个啥? 其实我们真的没必要把copy想的太高深.它之所以叫copy,其终极目的已不言而喻,

深拷贝 浅拷贝 引用计数

;深拷贝 浅拷贝 深拷贝(成员用到了指针存储空间地址)每个对象的成员都有自己独立的成员内存地址空间,造成了浪费 浅拷贝,把原对象的指针也直接拷贝过来我还是用的这一片空间,但是析构会有重复释放问题,解决重复释放用引用计数记录这个类产生了多少对象,析构的时候--引用计数就可以了 计数为0   delete 这块内存空间 ;引用计数技术 优点:所有对象共享同一片空间,间接的达到了对象间的数据共享 缺点:一旦一个对象改变了这片内存,那么所有的对象都受到影响 ;写时拷贝技术 当对象需要操作这一块空间存放数

c# 通用类型系统 深拷贝 浅拷贝 函数传参

c# 通用类型系统 及变量在 深拷贝 浅拷贝 函数传参 中的深层次的表现 在编程中遇到了一些想不到的异常,跟踪发现,自己对于c#变量在内存上的表现理解有偏差,系统的学习并通过代码实验梳理了各种情况下,变量在内存级的表现情况,对以后的coding应该有些帮助.在此记录以免忘记了... 1. 通用类型系统 先来一张图: 通用数据类型分为了值类型和引用类型. 我们定义一个int型实际上是一个system.int32的实例,在语法上我们像使用其他的类对象一样,但是,存储的的仍然是基本类型.这种把基本类型

深拷贝&amp;浅拷贝&amp;引用计数&amp;写时拷贝

(1).浅拷贝: class String { public: String(const char* str="") :_str(new char[strlen(str)+1]) { strcpy(_str,str); } ~String() { if(NULL!=_str) { delete[] _str; _str=NULL; } } private: char* _str; }; int main() { String s1("hello"); String

C++类拷贝控制 深拷贝 浅拷贝

普通类型对象之间的复制很简单,而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量,这篇文章将帮你理清C++类对象的拷贝方式 拷贝构造函数,拷贝赋值运算符 首先我们简单了解下默认的拷贝构造函数和拷贝赋值运算符 拷贝构造函数 第一个参数是自身类类型引用,其他参数都有默认值的构造函数就是拷贝构造函数 class Sales_data { public: Sales_data(); //默认构造函数 Sales_data(const Foo&); //默认拷贝构造函数 //... };

c++语法:拷贝构造函数(深拷贝浅拷贝)

以拷贝的方式初始化对象 初始化对象时会调用构造函数,不同的初始化方式会调用不同的构造函数: 如果用传递进来的实参初始化对象,那么会调用普通的构造函数,我们不妨将此称为普通初始化: 如果用其它对象(现有对象)的数据来初始化对象,那么会调用拷贝构造函数,这就是以拷贝的方式初始化. 对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数.但是当类持有其它资源时,例如动态分配的内存.指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定

Java 深拷贝浅拷贝 与 序列化

一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会进行拷贝:(引用的对象只要求浅拷贝即可:若要深层拷贝,一般可利用序列化和反序列化来实现,也可手动实现各级引用对象的深层拷贝:) 二.实现: 浅拷贝:实现Cloneable接口,重写clone()方法,在clone()调用父类super.clone()即可: 深拷贝:1. 实现Cloneable接口,