C++_CopyConstructor(副本构造器 防止指针重复释放)

来源:互联网 发布:社交网络 百度云盘 编辑:程序博客网 时间:2024/06/07 13:50

1.背景说明:

我们可以将一个对象赋值给一个类型与之相同的变量,编译器将生成必要的代码将 源对象 各属性的值分别赋值给 目标对象  的各成员,这种赋值行为称之为“逐位复制(copy)”,在绝大多数场合下都没有问题,但是如果某些成员是指针的话,问题就来了:对象成员进行逐位复制的结果就是:你将拥有两个一模一样的实例,而这两个副本里的同名指针将指向相同的地址!于是,当删除其中一个对象时,它所包含的指针也将被删除,若此时另外一个副本对象还在引用这个指针就会出现内存问题,导致程序崩溃。(“同时”删除两个对象,也是无效的,因为CPU是逐条指令执行的,总会有先后顺序)

2.解决方法一: 重载等号(=)操作符,新的指针使用新的的内存地址,原来的指针内存地址不变,并使用下列赋值:

Myclass obj1;

Myclass obj2;

obj1=obj2;

风险:若在创建obj2实例对象时直接初始化(Myclass obj2=obj1)则实际上编译器在编译时并不使用自定义的重载等号(=)操作符,而是去寻找副本构造器,若没有就会自行创建一个,依然会进行“逐位复制(copy)”,造成指针对象指向同一内存块!所以有了解决方法二:不让编译器自定义副本构造器,而是自定义一个副本构造器。

3.解决方法二:自定义副本构造器,在其中使用 重载等号(=)操作符

4.代码 as follows:

// CopyConstructor.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>class MyClass{public:MyClass(int *P);//主构造器 传入整型指针MyClass(const MyClass &rhs);//重载构造函数 副本构造器~MyClass();MyClass &operator=(const MyClass &rhs);//重载赋值操作符 返回类型依然是MyClassvoid print();private:int *ptr; //私有成员变量 指针类型        //验证:赋值操作时 两对象的指针类型成员 同时指向同一块地址,释放时 造成重复释放内存错误             //所以有了副本构造器,两对象赋值时,对指针成员 规划两块内存地址,存放同一个数值,地址释放时互不影响};//MyClass 成员定义MyClass::MyClass(int *p){std::cout << "Into MainConstructor\n";ptr = p;std::cout << "Leave MainConstructor\n";}MyClass::MyClass(const MyClass &rhs) {std::cout << "Into CopyConstructor\n";*this = rhs;//为方便使用这样的操作如 MyClass obj2=obj1;//定义时直接构造std::cout << "Leave CopyConstructor\n";}MyClass::~MyClass(){std::cout << "Into Destructor\n";delete ptr;//释放指针指向的内存块(指针还存在,但不指向任何内存)std::cout << "Leave Destructor\n";}MyClass & MyClass::operator=(const MyClass & rhs){std::cout << "Into Assignment OperatorOverloading\n";  //赋值操作符重载if (this != &rhs)//如 obj2=obj1;{delete ptr;      //删除新对象obj2.ptr指针成员 在定义时指向的地址ptr = new int;   //为新对象obj2.ptr指针成员 分配新的内存地址(即指向新的内存地址)*ptr = *rhs.ptr; //将原对象obj1.ptr指针指向的内容 存入新对象obj2.ptr新分配的地址中去 //结果:新对象obj2.ptr拥有了新地址;原obj1.ptr地址不变 }else {std::cout << "The Same Object on both sides of \"=\"  , No action!\n"; // obj1 = obj1;}std::cout << "Leave Assignment OperatorOverloading\n";  return *this;}void MyClass::print(){std::cout << *ptr << std::endl;}int main(){MyClass obj1(new int(1));//初始化obj1对象MyClass obj2(new int(2));obj2 = obj1;obj1.print();obj2.print();std::cout << "--------------------------------------------------\n";MyClass obj3(new int(3));MyClass obj4 = obj3;  //obj4定义 并初始化obj3.print();obj4.print();std::cout << "--------------------------------------------------\n";MyClass obj5(new int(5));obj5 = obj5;obj5.print();system("pause");    return 0;}


0 0