IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 2021-08-15 C++副本构造器-重载操作符=-调试图解 -> 正文阅读

[C++知识库]2021-08-15 C++副本构造器-重载操作符=-调试图解

引用案例自:https://blog.csdn.net/crow_n/article/details/51568848

两个指针指向同一个变量时,容易出问题

逐位复制(bitwise copy) :
众所周知,我们可以把 一个对象实例c1赋值给一个类型与之相同的对象c2(例如 MyClass c2=MyClass c1),在赋值过程中编译器将生成必要的代码把"源"对象各属性的值分别赋值给"目标"对象的对应成员,这种赋值行为被称为逐位复制(bitwise copy)。

逐位复制下的普通变量与指针变量 :
逐位赋值在绝大多数场合都是没有问题的,但如果某些成员变量是指针的话,问题就来了:
对象成员进行逐位复制的结果是你将拥有两个一模一样的实例,这两个实例的普通变量虽然名字一样,但是都有不同的地址(&c1和&c2不同)。而这两个副本实例的同名指针(c1.ptrInt和c2.ptrInt)变量却会指向相同的一个地址…

漏洞:
如果两个实例的同名指针变量指向着同一个地址,当删除其中一个对象,它包含的指针也将被删除,但万一此时另一个副本(对象)还在引用这个指针,便会出现问题!

我们都知道两个指针指向同一个变量时如果一个指针被释放那么另一个就会出问题
为了说明问题我做了一个很恶心的小例子

#include <iostream>
#include <string>

class C
{
public :
    C(int v)
    {
        ptrInt=new int;
        *ptrInt=v;
		
        valueInt = v;
    }
	
    ~C()
    {
		
    }
    void DelIntV()
    {
        valueInt=0;
        delete ptrInt;
    }
    
    C(const C& c)
    {
		
    }
    int * ptrInt;
    int valueInt;
private:
    
};


int main()
{
    C c1(2);
    C c2(3);
    c2=c1;
    std::cout<<"c2.ptrInt: "<<c2.ptrInt<<"c2.value "<<*c2.ptrInt<<std::endl;
    std::cout<<"c2.valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();
	
    std::cout<<"\n释放c1后:\nc2.ptrInt:"<<c2.ptrInt<<"c2.value: "<<*c2.ptrInt<<std::endl;
    std::cout<<"c2.valueInt: "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

在这里插入图片描述调试过程:
在这里插入图片描述
这是把c1赋值给了c2后把指针ptrInt的值输出和valueInt输出,再把c1的指针给delete,valueInt赋值为0,再输出c2的ptrInt和valueInt就会发现指针有问题。

这里记住,此时赋值完以后对象c2里成员指针变量的指向变了!!!

通俗的讲就是创建了c1、c2两个对象,赋值后把c2指到了c1身上。两个对象共用一套器官,c2对c1身体有了控制权,整型变量ValueInt是头发,c1释放以后,也就是c1自杀,器官都死了,c2随同一起死,但是指针释放不影响头发的存在。

为了解决这样的可以重载操作符=

重载操作符的意义在于,把:
(1)c2.ptrInt =c1.ptrInt ;
(2)c2.valueInt = c1.valueInt
两个东西变成:
(1)(*c2.ptrInt )=(*c1.ptrInt), 此处 c2.ptrInt不发生改变,改变的是指针里存放的值;
(2)c2.valueInt = c1.valueInt。

C& operator=(const C &c)
    {
        if(this!=&c)
        {
            delete ptrInt;
            ptrInt = new int;
            *ptrInt= *c.ptrInt;
            valueInt=c.valueInt;
        }
        return *this;
    }

完整代码

#include <iostream>
#include <string>

class C
{
public :
    C(int v)
    {
        ptrInt=new int;
        *ptrInt=v;
		
        valueInt = v;
    }
	
    ~C()
    {		
    }
    void DelIntV()
    {
        valueInt=0;
        delete ptrInt;
    }
    
    C(const C& c)
    {		
    }
    int * ptrInt;
    int valueInt;
	
    C& operator=(const C &c)
    {
        if(this!=&c)
        {
            delete ptrInt;
            ptrInt = new int;
            *ptrInt= *c.ptrInt;
            valueInt=c.valueInt;
        }
        return *this;
    }
private:
    
};


int main()
{
    C c1(2);
    C c2(3);
    c2=c1;
	std::cout<<"c2.ptrInt: "<<c2.ptrInt<<"c2.value "<<*c2.ptrInt<<std::endl;
    std::cout<<"c2.valueInt "<<c2.valueInt<<std::endl;
    c1.DelIntV();
	
    std::cout<<"\n释放c1后:\nc2.ptrInt:"<<c2.ptrInt<<"c2.value: "<<*c2.ptrInt<<std::endl;
    std::cout<<"c2.valueInt: "<<c2.valueInt<<std::endl;
    std::cin.get();
    return 0;
}

在这里插入图片描述重载时调试结果:
在这里插入图片描述释放c1时调试结果
在这里插入图片描述重载的时候构造释放了c2指针指向的内存,然后立马new了一块内存出来,此时c2指针指向的内存位置不变,只是c2指针没有控制权了,new了以后又重新恢复了控制权。

参考以下案例来理解重载操作符里面的两行代码 :
delete ptrInt;
ptrInt = new int;

#include
using namespace std;
void main()
{char*ch1;
ch1=new char(‘h’);
delete ch1;// 只是释放对象的内存空间
*ch1=‘a’;//这里又初始化对象,分配内存
cout<<*ch1<<endl;
}

delete是把堆上面的内存空间释放了,也就是告诉系统,这块内存可以被分配给其他人(因为你既然释放内存了,那系统肯定认为你不需要这块内存了),如果有其他人new后得到这块内存,那肯定会被分配给这个人,但是ch1指针仍然指向这块内存(如果你不做ch1=0的话),也可以对其进行任何操作,如果这块内存已经被分配给别人了,那你这时候通过ch1对其进行的操作可能会导致难以预料的严重后果,所以ch1=0很重要。而对于*ch1=‘a’;需要说明,ch1是放在栈上的,而字符‘a’也是在栈上,只是这时候ch1指向了‘a‘在栈上的地址,所以cout<<*ch1<<endl;肯定是输出a。

char*ch1,*ch2; ch1=new char(‘h’); delete ch1;
delete的时候,系统只是将指针指向的堆空间回收,但是没有将指针变量的值赋值为null,也就是说指针还是指向原来的堆空间,但是这个空间已经失效,所以delete一个指针以后要马上将它赋值为null,不然容易导致野指针的出现。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-16 11:33:49  更:2021-08-16 11:33:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 15:58:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计