zoukankan      html  css  js  c++  java
  • shallow copy & deep copy

    1、深复制与浅复制的概念


    ->浅复制(shallow copy)概念
     
    在SDK Guides中(搜索copy),官方给出的浅复制概念为:
    Copying compound objects, objects such as collection objects that can contain other objects, must also be done with care. As you would expect, using the = operator to perform a copy on these objects results in a duplication of the object reference. In contrast to simple objects like CFString and CFData, the “CreateCopy” functions provided for compound objects such as CFArray and CFSet actually perform a shallow copyIn the case of these objects, a shallow copy means that a new collection object is created, but the contents of the original collection are not duplicated—only the object references are copied to the new container.
     
    大致意思就是,在你对组合对象进行拷贝时,你拷贝的源对象指针指向的地址中内容,但是并不拷贝该内容中指针指向的内容;
     
    ->深复制(deep copy)概念
     
    同样的,官方给出的深复制概念为:
    When you want to create an entirely new compound object, you must perform a deep copyA deep copy duplicates the compound object as well as the contents of all of its contained objects.
     
    大致意思是,当你想完完全全创建一个新的组合对象时,你必须执行一次深拷贝,也就是说,你在拷贝这个组合对象包含的内容的同时,也必须拷贝该对象里指针指向的内容, 相对于浅拷贝,深拷贝多了一次递归行为,即不断的去拷贝该对象中包含的指针的指向的内容,当然,这个指针也可能是指向某个对象的,这时候就需要把该对象中的内容也一起拷贝。
     
    2、深复制与浅复制的对比举例
     
    为了加深理解,举个简单的例子,你的电脑中有这样一份文件

    我对“资源库”文件夹进行拷贝,浅拷贝的意思就是,我对“资源库”文件创建了一个副本(创建时是空的),并且把其中的文件复制一份放到“资源库 副本”中,然后把其中的文件夹放到“资源库 副本”中,但是这些文件夹里面并没有内容,(我们可以通过这个文件夹找到其中的内容,准确的说是将文件夹的替身放到“资源库 副本”中-复制指针或者叫文件夹对象),这时候改变“资源库”下面文件夹中的内容会影响到“资源库 副本”。如果是深拷贝,就相当于,我创建了一个“资源库”文件夹,然后将其中的内容,包括文件、文件夹以及文件夹下面的所有东西,完完整整的拷贝过去,放在另外一个地方。 

    3、代码举例
     
    -> 首先,我们需要明确,copy 与 mutableCopy 在Xcode中默认的操作方式是,在某个对象A调用该方法时,先开辟一块新的内存空间B,然后取出A指向的内容(如果是指针,仅仅取出指针)放到新开辟的空间B中[注意,仅仅是A指向内容,并不包括A指向的内容中指针指向的内容]拷贝一份放到新开辟的空间中,然后返回一个存有新开辟内存地址的对象给消息接收者。
     
    ->简单对象的copy与 mutableCopy
     

    #pragma mark 演示字符串的拷贝(浅拷贝)

    // 只有一种情况是浅拷贝:不可变对象调用copy方法时

    // 浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1

    void stringCopy() {

        NSString *string = [[NSString allocinitWithFormat:@"age is %i"10];

        NSLog(@"%zi", [string retainCount]);

        

        // copy产生的是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy会直接返回源对象本身

        // 源对象计数器会+1

        // 在浅拷贝情况下,copy其实就相当于retain

        NSString *str = [string copy];

        NSLog(@"%zi - %p -%p", [string retainCount],string, str);

       

        [str release];

        [string release];

    }

    #pragma mark 演示字符串的拷贝(深拷贝)

    // 深拷贝:内容拷贝,会产生新的对象。新对象计数器置为1,源对象计数器不变。

    void stringMutableCopy() {

        // string:1

        NSString *string = [[NSString allocinitWithFormat:@"age is %i"10];

        

        // 产生了一个新的对象,计数器为1。源对象的计数器不变。

        // str:1

        // string:1

        NSMutableString *str = [string mutableCopy];

        //NSLog(@"str:%zi", [str retainCount]);

        //NSLog(@"string:%zi", [string retainCount]);

        

        // strstring不是相同对象

        // NSLog(@"%i", str == string);

        

        [str appendString:@" abcd"];

        

        NSLog(@"string:%@", string);

        NSLog(@"str:%@", str);

        

        // str:0

        [str release];

        // string:0

        [string release];

    }

     

    总结, 上面的复制只是非组合对象的拷贝,在拷贝时,按照copy或者MutableCopy的默认操作方式进行,只是在由不可变对象复制到不可变对象时,系统为了节约性能就没有新创建这个不可变对象,其余时候还是都要新开辟内存空间,将源对象指向的内容放到新开辟空间中,只是简单的移动,不会进行多余的操作。
     
    ->组合对象(compound objects)的copy与 mutableCopy
     

            NSMutableString *str1 = [NSMutableString stringWithFormat:@"age = %d", 10];

            NSMutableString *str2 = [NSMutableString stringWithFormat:@"age = %d", 10];

            NSMutableString *str3 = [NSMutableString stringWithFormat:@"age = %d", 10];

            

            NSArray *array1 = @[str1, str2, str3];

           

           

            

            NSArray *array2 = [array1 copy];// 浅复制,仅仅是拷贝array1指向的内存地址存放的内容,此处是取出指针,放到array2中,所以array与array2存放的内容一样(都是指向str1,str2,str3的地址)

            NSLog(@"%p - %p - %p",array1[0], array1[1], array1[2]);

            NSLog(@"%p - %p - %p",array2[0], array2[1], array2[2]);

           

    个人感觉,理解深复制和浅复制的关键在于抓住复制的主要目的,即产生一个副本对象,在改变源对象或者副本对象时,不会影响另外一个,然后浅复制就是浅层次的复制,只复制表面的东西,深复制就是更深层次的复制,只要与之相关的全部复制过去。

    关键是理解清楚指针、指向指针的指针、copy的真正意义,之后再回头看深复制与浅复制,so easy。

  • 相关阅读:
    Python生成二维码
    SSO单点登录
    小说 · 凉生,我们可不可以不忧伤
    RabbitMQ入门教程——.NET客户端使用
    ASP.NET MVC 拓展ActionResult实现Html To Pdf 导出
    ASP.NET MVC 拓展ViewResult实现word文档下载
    RabbitMQ入门教程——安装及配置
    MongoDB学习笔记——分片(Sharding)
    MongoDB学习笔记——Replica Set副本集
    MongoDB学习笔记——Master/Slave主从复制
  • 原文地址:https://www.cnblogs.com/liufeng24/p/3491599.html
Copyright © 2011-2022 走看看