c/c++/c++11 浅拷贝和深拷贝

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c/c++/c++11 浅拷贝和深拷贝相关的知识,希望对你有一定的参考价值。

参考技术A

1.1 拷贝构造函
c++通过拷贝构造函数实现对象拷贝.所以先介绍一下拷贝构造函数.
实例:

CA A(100,"123")//构造函数赋值
CExample B=A;//拷贝构造函数赋值
CExample C(A);//拷贝构造函数赋值
CExample D; D=A;//赋值构造函数赋值
g_fun(A);//传值拷贝调用对象构造函数

拷贝构造函数实现分析:
调用g_Fun()时,会产生以下几个重要步骤:
(1).函数调用传值拷贝,会先会产生一个临时变量,就叫 C 吧。
(2).然后调用拷贝构造函数把A的值给C.整个这两个步骤有点像:CA C(A);
(3).等g_Fun()执行完后, 析构掉 C 对象。C对象完成了在g_Fun()函数内部的工作.
1.2 浅拷贝
浅拷贝只拷贝基本数据类型(非指针变量).
对于指针变量,对象B的指针变量会 指向 对象A的指针变量内存,不会拷贝.
类缺省拷贝构造函数是浅拷贝.上例中的拷贝构造函数的实现就是浅拷贝.
浅拷贝的问题是如果对象中变量带有指针,则会发生错误.因为两个指针指向同一个内存,一个对象修改,另一个对象的值也被更改了.
当在析构的时候,会发生两次free同一个内存,造成错误.

下面的link介绍了浅拷贝和c的简单神拷贝.c++深拷贝参见1.3节,c的高级深拷贝参见2.2节。
参见 https://blog.csdn.net/cyy_0802/article/details/80374812
1.3 c++深拷贝
在拷贝构造函数中分配内存,将入参对象的指针变量指向的内存,全部拷贝一份就是深拷贝。
实例分析

CA A(10,"Hello!");//构造函数初始化对象。
CA B=A; //拷贝构造函数.
上例将str的内容拷贝一份,实现了深拷贝.
扩展问题,如果类中变量不是char* str,而是另一个对象的指针会怎么样?

2.1 浅拷贝
和上面的c++浅拷贝一样. 两个指针指向同一个内存.

2.2 深拷贝
(1) 如果struct中没有指针变量
直接拷贝内存即可.

(2) 如果struct中带有指针变量
需要自己实现拷贝函数,将每个item拷贝一份.(实现类似c++的拷贝构造函数)

扩展情况:如果将char *data换成struct S_NodeA *nodeA会怎么样呢?

CopyStruct将非struct的item拷贝一份。nodeA需要嵌套拷贝.调用拷贝S_Node的函数CopyNode完成拷贝.
总结:浅拷贝就是指针赋值,不分配内存,两个指针指向一个内存. 深拷贝就是拷贝指针指向的内存.如果有嵌套对象的话,嵌套拷贝.

c++11 使用移动构造函数实现深拷贝
移动构造函数的原理是,指针A和B同时指向一块内存,然后将原来的A指针置NULL. 这样避免了两个指针指向同一个内存,也避免了内存拷贝.

JS中的浅拷贝和深拷贝。

//浅拷贝
var o1 = { a: 10, b: 20, c: 30 };
var o2 = o1;
o2.a = 100;
console.log(o1);

//深拷贝
var o1 = { a: 10, b: 20, c: 30 };
var o2 = { a: o1.a, b: o1.b, c: o1.c };
o2.a = 100;
console.log(o1);

//深拷贝 只适用于一维数组
var o1 = { a: 10, b: 20, c: 30 };
var o2 = { ...o1 };
o2.a = 100;
console.log(o1);

//简单深拷贝,将对象转成json字符串再转回来
var o1 = { a: { d: 40 }, b: 20, c: 30 };
var o2 = JSON.parse(JSON.stringify(o1));
o2.a.d = 100;
console.log(o1);

//多维数组
var o1 = { a: { d: 40 }, b: 20, c: 30 };
var o2 = { ...o1 };
o2.a.d = 88;
console.log(o1);

//Object.assign 能够实现一层深拷贝
var o1 = {
    name: "Gucci",
    age: 13,
    gender: "female",
    hobby: {
        a: ‘Chinese‘,
        b: ‘Math‘,
        c: ‘English‘
    }
};
var o2 = Object.assign({}, o1);
o2.hobby.a = "Math";
o1.age = 1000;
console.log(o1);


//终极大杀器 递归复制实现深拷贝

//注意typeof []结果为object
typeof []
"object"
typeof {}
"object"
typeof "111"
"string"
typeof null
"object"

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);

  

//运算结果按顺序打印
{ a: 100, b: 20, c: 30 }
{ a: 10, b: 20, c: 30 }
{ a: 10, b: 20, c: 30 }
{ a: { d: 40 }, b: 20, c: 30 }
{ a: { d: 88 }, b: 20, c: 30 }
{ name: ‘Gucci‘,
  age: 1000,
  gender: ‘female‘,
  hobby: { a: ‘Math‘, b: ‘Math‘, c: ‘English‘ } }
[ 2, 2, 3, 4 ] [ 1, 2, 3, 4 ]

  

以上是关于c/c++/c++11 浅拷贝和深拷贝的主要内容,如果未能解决你的问题,请参考以下文章

JS中的浅拷贝和深拷贝。

pyhton之浅拷贝(copy)和深拷贝(deepcopy)详解,举例说明

Javascipt 浅拷贝和深拷贝

python中的赋值浅拷贝和深拷贝

清晰易懂!讲解JS赋值浅拷贝和深拷贝

C#的浅拷贝和深拷贝