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

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

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 hql字符串字段中是否包含某个字符串,用 find_in_set

    有这样一个需求,在Mysql数据库字符串字段(权限)中,有范围在 1 到 N 之间代表不同权限的值,分别被','分开,现在要取出具有某权限的所有成员列表. 创建表: 1 CREATE TABLE us ...

  2. Consul 启动命令

    服务端: nohup consul agent -server -bootstrap-expect 1 -config-dir /etc/consul.d/ -data-dir /var/opt/co ...

  3. js 判断pc端或手机端

    <script> (function () { var navUA = navigator.userAgent; var defIncludeStr = "iPhone|Andr ...

  4. 今天说一下DML触发器的顺序

    因为05之后的版本允许了一个对象有多个after触发器,所以呢~顺序方面还是要留意一下下的.比如我现在要往一个测试表里面添加多个触发器. USE Test GO ,),Name )) GO CREAT ...

  5. Let's Encrypt 正式出發(免费HTTPS证书即将到来)

    转自:https://blog.gslin.org/archives/2015/10/20/6073/lets-encrypt-%E6%AD%A3%E5%BC%8F%E5%87%BA%E7%99%BC ...

  6. HTTP状态码206和416

    HTTP 2xx范围内的状态码表明了:"客户端发送的请求已经被服务器接受并且被成功处理了". TTP/1.1 200 OK是HTTP请求成功后的标准响应 HTTP/1.1 206状 ...

  7. Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法

    Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法 You can extract all the ...

  8. nginx参数说明

    一.nginx的核心配置: >>> 正常运行的必备配置: 1. user username [groupname]; #指定运行worker子进程的用户或组 2. pid /path ...

  9. nodejs模块——http模块

    http模块主要用于创建http server服务. 本文还用到url模块和path模块,还有fs模块.url模块用于解析url,path模块用于处理和转换文件路径. 一.简单应用 代码如下: // ...

  10. css3 border-radius

    前缀对应浏览器 前缀 浏览器 -webkit chrome和safari -moz firefox -ms IE -o opera border-radius: <style type=&quo ...