精华内容
参与话题
问答
  • 浅拷贝和深拷贝

    2018-08-08 11:21:38
    2、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。 b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。 fromkeys生成...

    解析

    1、b = a: 赋值引用,a 和 b 都指向同一个对象。

    2、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。

    b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。

    fromkeys生成新的字典时,值[1, {"Capital": "哈尔滨"},'2']进行的是浅拷贝,

    即对键黑龙江的值修改,当将[1, {"Capital": "哈尔滨"},'2']整体改为3时,只有键黑龙江的值的值变化了,即三个值是不同的对象

    对['吉林'][1]['Capital']进行修改时,哈尔滨的[1]['Capital']也被改变了,证明三个原始键值是不同的对象,但他们的值是相同的指向同一个子对象。

    province = dict.fromkeys(["黑龙江", "吉林", "辽宁"], [1, {"Capital": "哈尔滨"},'2'])
    print(province)
    {'黑龙江': [1, {'Capital': '哈尔滨'}, '2'], '吉林': [1, {'Capital': '哈尔滨'}, '2'], '辽宁': [1, {'Capital': '哈尔滨'}, '2']}
    province['黑龙江']=3
    print(province)
    {'黑龙江': 3, '吉林': [1, {'Capital': '哈尔滨'}, '2'], '辽宁': [1, {'Capital': '哈尔滨'}, '2']}
    province['吉林'][1]['Capital']=2
    print(province)
    {'黑龙江': 3, '吉林': [1, {'Capital': 2}, '2'], '辽宁': [1, {'Capital': 2}, '2']}

    展开全文
  • 一篇文章彻底搞懂浅拷贝和深拷贝

    万次阅读 多人点赞 2018-07-16 16:36:32
    强烈推荐30个原生JavaScript的demo,包括canvas时钟特效、自定义视频播放器、搜索栏快速匹配、fetch访问资源、console调试...浅谈深拷贝和浅拷贝 深拷贝和浅拷贝的区别 为什么要使用深拷贝? 深拷贝的要求程度...

    强烈推荐30个原生JavaScript的demo,包括canvas时钟特效、自定义视频播放器、搜索栏快速匹配、fetch访问资源、console调试技巧等,先fork后学习,详见点击打开链接,欢迎点赞~~~谢谢,共同进步学习!

     

    由博主《前端初级工程师面试系列一JS基础》文章一JS变量类型引伸的考点,变量类型分为基本类型和引用类型,那么在变量拷贝赋值时,也是不一样的,分为浅拷贝和深拷贝,是面试中常考的知识点,也是实际开发中经常会用到的内容。

    目录

    正文

    前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时我当然不会主动犯这个错误,但很多时候,一不小心可能就会修改了原来的对象,例如:var newObj = obj; newObj.xxx = xxx  实际上,这个时候newObj和obj两个引用指向的是同一个对象,我修改了newObj,实际上也就等同于修改了obj,这,就是我和深浅拷贝的第一次相遇。

    深拷贝和浅拷贝的区别

    1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

    2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

    为什么要使用深拷贝?

    我们希望在改变新的数组(对象)的时候,不改变原数组(对象)

    深拷贝的要求程度

    我们在使用深拷贝的时候,一定要弄清楚我们对深拷贝的要求程度:是仅“深”拷贝第一层级的对象属性或数组元素还是递归拷贝所有层级的对象属性和数组元素?

    怎么检验深拷贝成功

    改变任意一个新对象/数组中的属性/元素,     都不改变原对象/数组

    只对第一层级做拷贝

    深拷贝数组(只拷贝第一级数组元素) 

    1. 直接遍历
    var array = [1, 2, 3, 4];
    function copy (array) {
       let newArray = []
       for(let item of array) {
          newArray.push(item);
       }
       return  newArray;
    }
    var copyArray = copy(array);
    copyArray[0] = 100;
    console.log(array); // [1, 2, 3, 4]
    console.log(copyArray); // [100, 2, 3, 4]

    该方法不做解释(逃...)

    2. slice()

    var array = [1, 2, 3, 4];
    var copyArray = array.slice();
    copyArray[0] = 100;
    console.log(array); // [1, 2, 3, 4]
    console.log(copyArray); // [100, 2, 3, 4]

    slice() 方法返回一个从已有的数组中截取一部分元素片段组成的新数组(不改变原来的数组!)

    用法:array.slice(start,end) start表示是起始元素的下标, end表示的是终止元素的下标

    当slice()不带任何参数的时候,默认返回一个长度和原数组相同的新数组

    3. concat()

    var array = [1, 2, 3, 4];
    var copyArray = array.concat();
    copyArray[0] = 100;
    console.log(array); // [1, 2, 3, 4]
    console.log(copyArray); // [100, 2, 3, 4]

    concat() 方法用于连接两个或多个数组。( 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。)

    用法:array.concat(array1,array2,......,arrayN)

    因为我们上面调用concat的时候没有带上参数,所以var copyArray = array.concat();实际上相当于var copyArray = array.concat([]);也即把返回数组和一个空数组合并后返回

     

    但是,事情当然不会这么简单,我上面的标题是 “深拷贝数组(只拷贝第一级数组元素)”,这里说的意思是对于一级数组元素是基本类型变量(如number,String,boolean)的简单数组, 上面这三种拷贝方式都能成功,但对第一级数组元素是对象或者数组等引用类型变量的数组,上面的三种方式都将失效,例如:

    
    var array = [
      { number: 1 },
      { number: 2 },
      { number: 3 }
    ];
    var copyArray = array.slice();
    copyArray[0].number = 100;
    console.log(array); //  [{number: 100}, { number: 2 }, { number: 3 }]
    console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

    深拷贝对象

    1.直接遍历

    var obj = {
      name: '彭湖湾',
      job: '学生'
    }
    
    function copy (obj) {
       let newObj = {};
         for (let item in obj ){
           newObj[item] = obj
         }
         return newObj;
    }
     var copyObj = copy(obj);
    copyObj.name = '我才不是彭湖湾呢! 哼 (。・`ω´・)';
    console.log(obj); // {name: "彭湖湾", job: "学生"}
    console.log(copyObj); // {name: "我才不是彭湖湾呢! 哼 (。・`ω´・)", job: Object}

    该方法不做解释(逃...)

    2.ES6的Object.assign

    var obj = {
      name: '彭湖湾',
      job: '学生'
    }
    var copyObj = Object.assign({}, obj);
    copyObj.name = '我才不叫彭湖湾呢! 哼  (。・`ω´・)';
    console.log(obj);   // {name: "彭湖湾", job: "学生"}
    console.log(copyObj);  // {name: "我才不叫彭湖湾呢! 哼  (。・`ω´・)", job: "学生"}

    Object.assign:用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target),并返回合并后的target

    用法: Object.assign(target, source1, source2);  所以 copyObj = Object.assign({}, obj);  这段代码将会把obj中的一级属性都拷贝到 {}中,然后将其返回赋给copyObj

    3.ES6扩展运算符:

    var obj = {
        name: '彭湖湾',
        job: '学生'
    }
    var copyObj = { ...obj }
    copyObj.name = '我才不叫彭湖湾呢! 哼  (。・`ω´・)'
    console.log(obj.name) //   彭湖湾
    console.log(copyObj.name)  // 我才不叫彭湖湾呢! 哼  (。・`ω´・)

    扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中

    ⚠️注意:实际上,无论是使用扩展运算符(...)还是解构赋值,对于引用类型都是浅拷贝。所以在使用splice()、concat()、...对数组拷贝时,只有当数组内部属性值不是引用类型是,才能实现深拷贝。对多层嵌套对象,也即是存在,很遗憾,上面三种方法,都会失败:

    var obj = {
       name: {
          firstName: '彭',
          lastName: '湖湾'
       },
       job: '学生'
    }
    var copyObj = Object.assign({}, obj)
    copyObj.name.lastName = '湖水的小浅湾';
    console.log(obj.name.lastName); // 湖水的小浅湾
    console.log(copyObj.name.lastName); // 湖水的小浅湾

    拷贝所有层级

    有没有更强大一些的解决方案呢?使得我们能够

    1.不仅拷贝第一层级,还能够拷贝数组或对象所有层级的各项值

    2. 不是单独针对数组或对象,而是能够通用于数组,对象和其他复杂的JSON形式的对象

    请看下面:

    下面这一招可谓是“一招鲜,吃遍天”

    1.JSON.parse(JSON.stringify(XXXX))

    var array = [
        { number: 1 },
        { number: 2 },
        { number: 3 }
    ];
    var copyArray = JSON.parse(JSON.stringify(array))
    copyArray[0].number = 100;
    console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
    console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

    JSON.parse() 方法用于将一个 JSON 字符串转换为对象--(反序列化)

    JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串--(序列化)

    序列化的缺点:

    1. 不支持基本数据类型的undefined,序列化后将其省略
    2. 不支持函数
    3. Nan,Infinity序列化的结果是null

    能用大招杀的就不要用q杀嘛!!

    2.手动写递归

    你说啥? 你说上面的那种方法太无脑,  一定要自己写一段递归才有做技术的感觉? OK成全你!

    let array = [
       { number: 1 },
       { number: 2 },
       { number: 3 }
    ];
    function copy (obj) {
            //首先判断需要拷贝的“东西”是什么类型
            if(typeof obj !== 'object' || obj == null){
                return;
            }
            let newobj = obj.constructor === Array ? [] : {};
            //obj是数组类型,下面的i就是index;obj是对象,i就是key
            for(let i in obj){
               newobj[i] = typeof obj[i] === 'object' ? copy(obj[i]) : obj[i];
            }
            return newobj
    }
    
    let copyArray = copy(array)
    copyArray[0].number = 100;
    console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
    console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

    【注意】上文的所有的示例都忽略了一些特殊的情况: 对对象/数组中的Function,正则表达式等特殊类型的拷贝

    上述代码中还隐藏这两个知识点:

    (1)obj == null 为何不是 obj === null?

    obj==null =>obj为null 或者 obj 为undefined,因为null == undefined,这样写能默认处理两种情况,obj===null ,成立前提只有obj是null

    (2)怎样判断一个对象是不是数组?

    先上方法(确定的方法有两种)

    1. 根据对象的class属性来判断,跨原型链调用toString()方法。  Object. prototype.toString.call(obj)===[ object Array]
    2. Array.isArray直接判断   Array. isArray(obj)。

    补充:

    • 推荐文章:为什么用Object.prototype.toString.call(obj)检测对象类型

      toString为Object的原型方法,返回一个用来描述该对象的字符串,所以可以调用对象原型方法toString()来探明对象的信息。
      那么原型方法怎么调用呢,利用call,将其this指向需要判断的对象, 就可以用toString()方法了。
      let arr=[1,2,3];
      console.log(Array.prototype.hasOwnProperty("toString"));//true
      console.log(arr.toString());//1,2,3 arr作为对象Object的实例,重写了toString()方法。
      delete Array.prototype.toString;//delete操作符可以删除实例属性
      console.log(Array.prototype.hasOwnProperty("toString"));//false
      console.log(arr.toString());//"[object Array]" 
      // 由于删除了实例对象中的toString()方法,找不到,顺着原型链往上走,就调用了对象Object的方法,返回的结果就和Array.prototype.toString(arr)一样的。
    • 根据构造函数来判断 instanceof 操作符可以来表示实例是否属于某个构造函数创建的。

    这种方法有一个问题,就是验证不够严格。 即使对象创建时不是使用数组创建的,但是只要原型链上有数组类型,也认为是数组,亦或者,即便创建时是数组创建,但其原型上有对象类型,便不再被认为是数组。

    推荐文章

    (3)for...in 和for...of,forEach的区别,for...in用于对象复制时需要注意什么?

    for... in特点

    • 遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。

    • for ... in 会遍历原型上的属性值

    • 遍历返回数据是乱序

    总结一句: for in 循环特别适合遍历对象。

    for... of特点

    • for of遍历的只是数组内的元素,而不包括数组的原型属性method和索引name

    • for ... in 会遍历原型上的属性值

    • 遍历返回数据是乱序

    • for of 不同与 forEach, 它可以与 break、continue和return 配合使用,也就是说 for of 循环可以随时退出循环。

    总结一句: for of 比较适合遍历数组,及其他具有遍历器的集合

    forEach特点

    • 使用foreach遍历数组的话,使用break不能中断循环,使用return也不能返回到外层函数。forEach与break和return 不搭

    • forEach()无法在所有元素都传递给调用的函数之前终止遍历

    for…in循环可应用于对象的复制,不过其有一个缺点,就是会从原型属性里继承prototype()属性。 

    例如: 

    let array = [1,2,3,4,5] 
    Array.prototype.age = 13;
    var result = []; 
    for(let i in array){ 
        result.push(array[i]); 
    } 
    alert(result.join(“,”)); 
    result返回结果【1,2,3,4,5,13】 

    如何避免从原型属性里继承prototype()属性,这里使用hasOwnProperty(name),该函数指示一个对象自身(不包括原型链)是否具有指定名称的属性。如果有返回true,如果没有返回false。 

    let array = [1,2,3,4,5] 
    Array.prototype.age = 13; 
    var result = []; 
    for(let i in array){ 
    if(array.hasOwnProperty(i)){ 
        result.push(array[i]); 
    } 
    alert(result.join(“,”)); 
    } 
    result返回结果【1,2,3,4,5】

    所以上面的深拷贝代码应优化为如下: 

    let array = [
       { number: 1 },
       { number: 2 },
       { number: 3 }
    ];
    function copy (obj) {
            //首先判断需要拷贝的“东西”是什么类型
            if(typeof obj !== 'object' || obj == null){
                return;
            }
            let newobj = Array.isArray(obj) ? [] : {};
            //obj是数组类型,下面的i就是index;obj是对象,i就是key
            for(let i in obj){
               if(obj.hasOwnProperty(i)){
                   newobj[i] = typeof obj[i] === 'object' ? copy(obj[i]) : obj[i];
                }
            }
            return newobj
    }
    
    let copyArray = copy(array)
    copyArray[0].number = 100;
    console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
    console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

    存在大量深拷贝需求的代码——immutable提供的解决方案

    实际上,即使我们知道了如何在各种情况下进行深拷贝,我们也仍然面临一些问题: 深拷贝实际上是很消耗性能的。(我们可能只是希望改变新数组里的其中一个元素的时候不影响原数组,但却被迫要把整个原数组都拷贝一遍,这不是一种浪费吗?)所以,当你的项目里有大量深拷贝需求的时候,性能就可能形成了一个制约的瓶颈了。

    immutable的作用

    通过immutable引入的一套API,实现:

    1.在改变新的数组(对象)的时候,不改变原数组(对象)

    2.在大量深拷贝操作中显著地减少性能消耗

    先睹为快:

    const { Map } = require('immutable')
    const map1 = Map({ a: 1, b: 2, c: 3 })
    const map2 = map1.set('b', 50)
    map1.get('b') // 2
    map2.get('b') // 50
    展开全文
  • C++细节 深拷贝和浅拷贝(位拷贝)详解

    万次阅读 多人点赞 2018-08-07 21:00:14
    前提  在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造...位拷贝...

    前提 

    在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数。

    阅读《高质量的c c++编程》,第9章有这样一段话,类似的话在《c++primer》《effective C++》都有所提及,那就是拷贝构造函数问题,这个是类编写者的一个基础问题。

    位拷贝(浅拷贝)举例,a指向b,b的改变其实会影响a的改变,同时a原本指向的空间发生泄漏。

    然后这种情况下有了深拷贝。

    我对其绘制思维导图,方便阅读并用分点的方式进行总结;

     

    何时调用?

    以下情况都会调用拷贝构造函数:
    一个对象以值传递的方式传入函数体
    一个对象以值传递的方式从函数返回
    一个对象需要通过另外一个对象进行初始化。

     

    浅拷贝:位拷贝,拷贝构造函数,赋值重载

    多个对象共用同一块资源,同一块资源释放多次,崩溃或者内存泄漏

     

    深拷贝:每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。

    缺省拷贝构造函数在拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标--浅拷贝。

    我们用自己编写的string举例

    
    class String
    {
    
    public:
    	const char* c_str()
    	{
    		return _str;
    	}
    
    	String(const char* str = "")
    		:_str(new char[strlen(str) + 1])
    	{
    		strcpy(_str, str);
    	}
    	String(const String &s)
    		:_str(NULL)
    	{
    		String tmp(s._str);
    		swap(_str, tmp._str);
    	}
    	~String()
    	{
    		if (_str)
    		{
    			delete[]_str;
    		}
    	}
    
    private:
    	char* _str;
    
    };
    

    通过开辟空间的方式,进行深拷贝

    	String s1("字符串1");
    	String s2(s1);
    	cout << s2.c_str() << endl;

    拷贝成功;

    这种方式采取的  拷贝构造,注意这个

    	String(const String &s)
    		:_str(NULL)
    	{
    		String tmp(s._str);
    		swap(_str, tmp._str);
    	}

    代码解析:其中this指向拷贝的对象,s指向试图拷贝的原对象。(测试中的  this指向s2,s指向s1)

    其中利用构造函数开辟空间,建立临时的tmp,然后进行交换完成拷贝。

    当然,我们也可以使用赋值操作符重载完成这一功能(如例子s1=s2)

    	String& operator =(const String& s)
    	{
    		if (this != &s)
    		{
    			String tmp(s._str);
    			swap(tmp._str, _str);
    			return *this;
    		}
    	}//调用构造析构
    //本代码是tmp调用的构造函数
    	String(const char* str = "")
    		:_str(new char[strlen(str) + 1])
    	{
    		strcpy(_str, str);
    	}
    /*String tmp(s._str)
    调用这个构造函数,开辟空间,建立一个和s1一样大小的空间,并拷贝值
    */
    

     

    代码解析:

    s1(this),s2(s)

    建立tmp,tmp有和s2一样大的空间,一样的数值(调用构造函数),然后交换使s1(this)指向2号空间,获得拷贝,tmp指向3号空间,tmp生命周期结束调用析构函数释放,功能完成。

     

     

    当然 赋值重载函数可以写的更加简洁

    	String &operator=(String s)
    	{
    		swap(_str, s._str);
    		return *this;
    	}

    利用tmp的方式是 借助构造函数,这一种方式则是借助拷贝构造函数

    展开全文
  • 浅拷贝”与“深拷贝”

    万次阅读 热门讨论 2009-07-05 11:07:00
    C++中对象的复制就如同“克隆”,用一个已有的对象快速地复制出多个完全相同的对象。一般而言,以下三种情况都会使用到对象的复制:(1)建立一个新对象,并用另一个同类的已有对象对新对象进行初始化,例如:class ...

     

           C++中对象的复制就如同“克隆”,用一个已有的对象快速地复制出多个完全相同的对象。一般而言,以下三种情况都会使用到对象的复制:

    1)建立一个新对象,并用另一个同类的已有对象对新对象进行初始化,例如:

     

           2)当函数的参数为类的对象时,这时调用此函数时使用的是值传递,也会产生对象的复制,例如:

           3)函数的返回值是类的对象时,在函数调用结束时,需要将函数中的对象复制一个临时对象并传给改函数的调用处,例如:

    对象的复制都是通过一种特殊的构造函数来完成的,这种特殊的构造函数就是拷贝构造函数(copy constructor,也叫复制构造函数)。拷贝构造函数在大多数情况下都很简单,甚至在我们都不知道它存在的情况下也能很好发挥作用,但是在一些特殊情况下,特别是在对象里有动态成员的时候,就需要我们特别小心地处理拷贝构造函数了。下面我们就来看看拷贝构造函数的使用。

        一、默认拷贝构造函数

           很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:

     

     

     

           当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象的复制问题,那就错了,让我们来考虑以下一段代码:

           这段代码对前面的类进行了一下小小的修改,加入了一个静态成员,目的是进行计数,统计创建的对象的个数,在每个对象创建时,通过构造函数进行递增,在销毁对象时,通过析构函数进行递减。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。出现这些问题最根本就在于在复制对象时,计数器没有递增,解决的办法就是重新编写拷贝构造函数,在拷贝构造函数中加入对计数器的处理,形成的拷贝构造函数如下:

           自己编写拷贝构造函数又可以分为两种情况——浅拷贝与深拷贝。

     

        二、浅拷贝

           所谓浅拷贝,指的是在对象复制时,只是对对象中的数据成员进行简单的赋值,上面的例子都是属于浅拷贝的情况,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,让我们考虑如下一段代码:

           在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分配的内容没有进行正确的操作。我们来分析一下:

           在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:

     

           在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,所以此时rect1.prect2.p具有相同的值,也即这两个指针指向了堆里的同一个空间,如下图所示:

     

           当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。

     

        三、深拷贝

           在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:

           此时,在完成对象的复制后,内存的一个大致情况如下:

     

     

    此时rect1prect2p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。

           此外,在与“对象的复制”很类似的“对象的赋值”的情况下,也会出现同样的问题。在“对象的赋值”一文中再来讨论此问题。

           通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。

     

     

     

     

    参考文献: 

    C++程序设计》  谭浩强

    C++编程思想 1卷》   Bruce Eckel

     

     

     

    展开全文
  • 什么是深拷贝与浅拷贝

    千次阅读 2018-11-21 14:26:27
    浅拷贝: 对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。注意:当内存销毁的时候,只想对象的指针,必须重新定义,才能够使用 代码: var a = {x:1} var b = a console.log(b);//{x:1} b.x = 2 ...
  • 深拷贝浅拷贝的理解

    2020-11-16 11:31:52
    如上,通过对数组的for循环,即可实现对数组的深拷贝了。 通过Array对象的纯函数能更快的实现一层深拷贝:[2,3,5,7,11].map(x=>x)
  • 深拷贝和浅拷贝

    2017-09-20 20:18:11
    浅拷贝 所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了
  • 终于弄清楚JS的深拷贝和浅拷贝了-读这一篇就够了

    万次阅读 多人点赞 2018-07-27 17:22:14
    今天,CVTE面试官问了深拷贝和浅拷贝的问题 我的回答是:浅拷贝是拷贝了对象的引用,当原对象发生变化的时候,拷贝对象也跟着变化;深拷贝是另外申请了一块内存,内容和原对象一样,更改原对象,拷贝对象不会发生...
  • 浅谈深拷贝和浅拷贝(js)

    万次阅读 多人点赞 2018-10-05 15:11:06
    如何区分深拷贝与浅拷贝?简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明是浅拷贝,如果B没变,那就是深拷贝。深入点来说,就是B复制了A,如果B复制的是A的引用,那就是浅拷贝...
  • 浅拷贝和深拷贝的区别?

    万次阅读 2018-08-10 13:46:34
    概述:  浅拷贝可以使用列表自带的copy()函数(如...  如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象...
  • 浅拷贝与深拷贝

    2020-10-06 10:14:12
    没有经过重载,"=" 的作用就是把左边的变量变得和右边的相等,即执行逐个字节拷贝的工作,对于指针变量,会使得两个指针指向同一个地方,这样的拷贝就叫做“浅拷贝”。 将一个指针变量指向的内容复制到另一个指针...
  • Java深入理解深拷贝和浅拷贝区别

    万次阅读 多人点赞 2019-02-13 23:31:47
    一、拷贝的引入 (1)、引用拷贝 创建一个指向对象的引用变量的拷贝。 Teacher teacher = new Teacher("Taylor",26); Teacher otherteacher = teacher; System.out.println(teacher); System.out.println...
  • 深拷贝和浅拷贝区别是什么?

    万次阅读 多人点赞 2019-06-18 15:44:47
    深拷贝和浅拷贝区别是什么? 复制一个 Java 对象 浅拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量 变量指向堆内存中的对象的指针,不复制堆内存中的对象。 深拷贝:复制基本类型的属性;...
  • 一:浅拷贝 function deep(obj){ var mn = {}; for(var key in obj) { mn[key] = obj[key] } return mn; } var obj0 = deep(obj); //对象 var obj1 = Object.assign({},obj); var {...obj2} = obj; //扩展...
  • js中的深拷贝和浅拷贝与值传递引用传递有着些许的关联,都是根据堆栈中数据的储存来传递数据。 下面主要说一下我对深拷贝和浅拷贝的理解: 简单举个例子来说明;当我们声明一个a变量并且赋值,并且让b等于a,...
  • 深拷贝和浅拷贝区别 JavaScript中有两种类型的对象拷贝:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。 最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用。 浅拷贝 —-只是拷贝了基本类型的数据...
  • python的复制,深拷贝和浅拷贝区别

    万次阅读 多人点赞 2019-06-05 09:43:49
    python的复制,深拷贝和浅拷贝区别 在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, alist=...
  • Java 的深拷贝和浅拷贝区别

    千次阅读 2018-06-26 11:19:58
    如果一个对象内部只有基本数据类型,那用 clone() 方法获取到的就是这个对象的深拷贝,而如果其内部还有引用数据类型,那用 clone() 方法就是一次浅拷贝的操作。 1.浅拷贝 对基本数据类型进行值传递,对引用...
  • c++深拷贝和浅拷贝

    万次阅读 多人点赞 2014-10-06 19:27:49
    C++中类的拷贝有两种:深拷贝浅拷贝当出现类的等号赋值时,会调用拷贝函数 在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝...
  • Java基础-深拷贝和浅拷贝区别

    千次阅读 2018-05-17 17:12:02
     深拷贝浅拷贝一般来说,拷贝的类型分为 深拷贝浅拷贝。|—————————————————————————————|| 深拷贝:引用对象的值等信息,复制一份一样的。 || 浅拷贝:只复制引用,另一处修改...

空空如也

1 2 3 4 5 ... 20
收藏数 102,884
精华内容 41,153
关键字:

浅拷贝