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

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

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();
    ;
}

这是把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();
    ;
}

再看一下输出结果:

这下就正确了吧,但是如果 我们在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();
    ;
}

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

编译器将在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();
    ;
}

结果

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

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

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

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

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

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

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

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

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

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

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

  6. Duilib源码分析(二)控件构造器—CDialogBuilder

    上一节了解了大体流程,但是界面控件元素是如何被加载.解析.构建.管理.控件消息如何处理的呢?接下来我们将结合控件构造器进行分析: CDialogBuilder:控件构造器,主要用以解析xml配置文件并 ...

  7. python列表副本

    a=[1,2,3] b=[4,5,6] a=a+b #创建含a和b的副本的新列表 a [1, 2, 3, 4, 5, 6] b [4, 5, 6] c=a+b #创建含a和b的副本的新列表c [1, ...

  8. 验证mongodb副本集并实现自动切换primary~记录过程

    接 验证mongodb主从复制过程 1.创建数据目录 同 验证mongodb主从复制过程 的实验一样,本次实验也是采用直接指定启动参数来启动mongodb数据库,本次实验我们需要启动三个数据库,为了与 ...

  9. java面向对象_构造器

    构造器(构造方法):是类中定义的方法. 1)常常用于给成员变量赋值: 2)与类同名,没有返回值类型,也不能写void: 3)在创建对象时被自动调用.所以构造方法的访问修饰符要用public,才能被自动 ...

随机推荐

  1. 初识WEB:输入URL之后的故事

    1. 概述2. HTTP请求过程3. 相关性能检测及优化手段4. 浏览器的呈现过程5. 浏览器的呈现引擎6. 引用及延伸阅读 概述 为什么输入www.cnblogs.com之后敲一个回车,浏览器就会显 ...

  2. Azure PowerShell (11) 使用自定义虚拟机镜像模板,创建Azure虚拟机并绑定公网IP(VIP)和内网IP(DIP)

    <Windows Azure Platform 系列文章目录> 前提要求: 1.假设笔者捕获一个Azure虚拟机模板,命名为leistorage 关于Azure虚拟机模板,请参考下图: 2 ...

  3. vs code插件记录

    最近一段时间一直在迷恋vs code,使用了一段时间,发现它即精简又快速,安装插件又快又稳定而且插件说明也很详细,是一款继sublime后少得的良心前端编辑器,配合上一些插件可以补全一些不足以更趋向于 ...

  4. 长链接转换成短链接(iOS版本)

    首先需要将字符串使用md5加密,添加NSString的md5的类别方法如下 .h文件 #import <CommonCrypto/CommonDigest.h> @interface NS ...

  5. Ansible Tower

    # Generated by iptables-save v1.4.7 on Tue Aug 23 04:58:34 2016 *filter :INPUT ACCEPT [0:0] :FORWARD ...

  6. easy-ui JOB 及 小记录

    $:获取  $.ajax({             type: "POST" ,             url: "" ,             cont ...

  7. js实现图片加载特效(从左到右,百叶窗,从中间到两边)

    /* 网上百度的,感觉”从中间到两边“的效果写的不是很好,改了一下,感觉可以了!*/<html> <head> <title></title> < ...

  8. Webform(内置对象-Response与Redirect、QueryString传值、Repeater删改)

    一.内置对象(一)Response - 响应请求对象1.定义:Response对象用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应.Response对象只提供了一个数据集合cookie, ...

  9. Tor

    参考: http://www.douban.com/group/topic/67555786/ http://blog.sina.com.cn/s/blog_72a7ac670101km46.html ...

  10. ajax提交含有html数据时的处理方法

    这两天在做一个文章内修改的功能,由于前端选用的Extjs控件库,于是就使用Ext.form.HtmlEditor. 在使用ajax提交数据的时候,需要提交包含有html代码的数据.这时候问题就来了,不 ...