我们都知道两个指针指向同一个变量时如果一个指针被释放那么另一个就会出问题

为了说明问题我做了一个很恶心的小例子

class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
delete ptrInt;
} C(const C& c)
{ }
int * ptrInt;
int valueInt;
private: }; int main()
{
C c1();
C c2();
c2=c1;
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}

这是把c1赋值给了c2后把指针ptrInt的值输出和valueInt输出,再把c1的指针给delete,valueInt赋值为0

再输出c2的ptrInt和valueInt就会发现指针有问题,看一下输出结果:

已经不对了吧。

为了解决这样的问题我第一个想到的就是重载操作符=

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

完整代码

class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
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();
C c2();
c2=c1;
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}

再看一下输出结果:

这下就正确了吧,但是如果 我们在main函数里做一个修改

int main()
{
C c1();
C c2=c1;//这里直接赋值
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}

这样后错误就又和之前一样了,为什么呢,

编译器将在c类里找一个副本构造器(copy constructor)如果找不到它会自己创建一个,

即使我们对操作符=进行了重载也没有用,由编译器自己创建的副本构造器仍会以"逐们复制"

的方式把c1赋值给c2

这样我们还要重新实现这个副本构造器,

className(const className &cn);

我是这样做的

    C(const C& c)
{
*this=c;
}

这里的=其实就是调用的重载的=方法

完整代码

class C
{
public :
C(int v)
{
ptrInt=new int;
*ptrInt=v; valueInt = v;
} ~C()
{ }
void DelIntV()
{
valueInt=;
delete ptrInt;
} C(const C& c)
{
*this=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();
C c2=c1;//这里直接赋值
std::cout<<"ptrInt "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
c1.DelIntV(); std::cout<<"address "<<c2.ptrInt<<" value "<<*c2.ptrInt<<std::endl;
std::cout<<"valueInt "<<c2.valueInt<<std::endl;
std::cin.get();
return ;
}

结果

c++ 副本构造器的更多相关文章

  1. 小甲鱼C++笔记(下)25-48

    二十五  二十六  二十七  重载 运算符重载 1. 作为成员函数 #include <iostream> using namespace std; class Add { private ...

  2. java源码解析之String类(二)

    上一节主要介绍了String类的一些构造方法,主要分为四类 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并 ...

  3. js--使用构造器函数来新建对象及操作

    通过new操作符来调用函数,来达到访问对象this值得目的,构造器将其创建的对象返回给我们. 直接上代码 //创建构造器函数 function Gadget(name, color){ this.na ...

  4. JavaSE——面向对象与面向过程、类与对象、(属性、方法、构造器)等

    一:面向对象与面向过程 二者都是一种思想,面向对象是相对于面向过程而言的. 面向过程: 1.面向过程思想强调的是过程(动作). 2.在面向过程的开发中,其实就是面向着具体的每一个步骤和过程,把每一个步 ...

  5. 6、Java类、对象、构造器、引用类型内存基本知识、引用类型值传递

    1.面向对象三大特征: 封装:encapsulation 继承:inheritance 多态:polymorphism 2.类中 数据特征(property):属性(attribute)静态的stat ...

  6. 一文了解 Java 中的构造器

    摘要:Java 也采用了构造器,并且还提供了一个垃圾收集器(garbage collector),当不再使用内存资源的时候,垃圾收集器会自动将其释放. 本文分享自华为云社区<一文带你了解 Jav ...

  7. Kafka副本管理—— 为何去掉replica.lag.max.messages参数

    今天查看Kafka 0.10.0的官方文档,发现了这样一句话:Configuration parameter replica.lag.max.messages was removed. Partiti ...

  8. Java之类的构造器(反射)

    反射: Java反射机制:指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法.这种动态获取类的内容以及动态调用对象的 ...

  9. Swift3.0P1 语法指南——构造器

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

随机推荐

  1. 更换mysql数据目录后出现ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) 的解决办法

    服务器上的mysql默认数据目录为/var/lib/mysql/,同时服务器的/空间不是很大,而近期又有大量的日志需要导入进行分析,时常搞得/的空间捉襟见肘,晚上一狠心就想把mysql的数据目录转移到 ...

  2. maven-shade-plugin

    <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> ...

  3. 初次体验VS2015正式版,安装详细过程。

    本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 阅读目录 介绍 安装 其他 本文版权归mephi ...

  4. org.apache.jasper.JasperException: Unable to compile class for JSP

    项目启动时报错 : The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory S ...

  5. SQL Server 2008 R2——ROW_NUMBER() 去掉不同行中相同列的重复内容

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  6. Kafka三款监控工具比较(转)

    在之前的博客中,介绍了Kafka Web Console这 个监控工具,在生产环境中使用,运行一段时间后,发现该工具会和Kafka生产者.消费者.ZooKeeper建立大量连接,从而导致网络阻塞.并且 ...

  7. mongo数据备份及恢复脚本

    #!/bin/bashtime="$(date +"%Y.%m.%d")" id=`echo "show dbs;"|/usr/local/ ...

  8. linux基础-基本命令的讲解(1-7单元)

    基本命令的讲解 主要内容介绍 1.LINUX操作系统安装及初始化配置(熟悉):2.LINUX操作系统目录组成结构及文件级增删改查操作(重点):3.LINUX操作系统用户.权限管理(重点):4.开源软件 ...

  9. python抓取网页中图片并保存到本地

    #-*-coding:utf-8-*- import os import uuid import urllib2 import cookielib '''获取文件后缀名''' def get_file ...

  10. Android Fragment初探:静态Fragment组成Activity

    一直习惯了在Activity中写所有事件处理代码,直到认真学习Fragment时,才发现,Activity完全可以由多个Fragment组成. 对Fragment的了解还不够深入,先从静态Fragme ...