谈谈我理解的拷贝

作者: 南京在下大暴雨 | 来源:发表于2016-08-04 17:46 被阅读163次
认为系统容器类的不可变拷贝即为浅拷贝而可变拷贝为深拷贝这是完全错误的概念

这段时间在跟周围开发者讨论的过程中,发现大部分情况下我们很难区分清楚开发中涉及的各种拷贝。
比如深拷贝浅拷贝、指针拷贝和对象拷贝以及object-c中系统容器类特有的不可变拷贝和可变拷贝。
更有人曾经就简单粗暴的将深拷贝解析为可变拷贝,将浅拷贝解析为不可变拷贝(如题图所示)。
这里首先要严肃说明的是,认为系统容器类的不可变拷贝即为浅拷贝而可变拷贝为深拷贝这是完全错误的概念

那么这几个概念到底该如何解析?下面我就从我自己理解的角度来帮助大家分析:

1. 深拷贝和浅拷贝

探讨深拷贝和浅拷贝最多的实际是在C++的项目中。例如我们有一个CMessage类,只定义了了一个指针成员pReceiver,同时定义并实现其默认的构造函数析构函数。

// 类定义
class CMessage{
    int* pReceiver;

public:
    CMessage();
    ~CMessage();
    CMessage(const CMessage&);
};


// 类实现
#include "CMessage.hpp"

CMessage::CMessage()
{
    pReceiver = new int(0);
}

CMessage::~CMessage()
{
    delete pReceiver;
    pReceiver = null;
}

实际上此时,编译器还会帮我们生成一个拷贝构造函数:

CMessage::CMessage(const CMessage& resMsg)
{
    pReceiver = resMsg.pReceiver;
}

由于这个拷贝构造并未对指针成员进行内容拷贝,只是复制了其地址,所以在用到拷贝赋值的地方,实际会出现复制出来的对象和被复制对象的成员pReceiver实际指向了同一块内存。
这就是经常被大家提起的浅拷贝。
为解决浅拷贝带来的内存访问冲突问题,所以引入了深拷贝。如,对于上面的代码示例,将拷贝构造函数改成如下方式,即实现了深拷贝。

CMessage::CMessage(const CMessage& resMsg)
{
    pReceiver = new int;
    *pReceiver = *resMsg.pReceiver;
}

由此,不难看出,深拷贝和浅拷贝实际探讨的是在对象拷贝时对其指针成员的赋值方式是内容拷贝还是地址拷贝的问题

2. 指针拷贝和对象拷贝

这里所说的指针拷贝实际就是上面提到的地址拷贝,而对象拷贝即上面的内容拷贝。
如何理解这个概念呢,还是拿上面的C++代码的例子。
假设我们有两个函数,AddressCopy和ContentCopy,分别实现的指针拷贝和对象拷贝。
则它们的实现当如下:

// pMsgB指针拷贝msgA
void AddressCopy()
{
    CMessage msgA;
    CMessage *pMsgB = &msgA;
}

// pMsgB对象拷贝msgA
void ContentCopy()
{
    CMessage msgA;
    CMessage *pMsgB = new CMessage(msgA);
}

由上面的代码可看出,指针拷贝和对象拷贝实际探讨的是指针对象的赋值方式是直接指向原始对象还是指向跟原始对象拥有相同值的新对象的问题

3. OC中的copy和mutableCopy

里所说的指针拷贝实际就是上面提到的地址拷贝,而对象拷贝即上面的内容拷贝。
OC中的copy和mutableCopy实际就是前面提到的可变拷贝和不可变拷贝,分别遵循NSCopying和NSMutableCopying协议。
因为OC中这两个协议都需显式实现才支持,所以对于自定义类,因开发者的实现而异。
系统容器类均实现了上面的协议,所以我们下面来看看系统容器类的这两种拷贝。

NSString* testA = @"测试消息内容";

// 不可变拷贝
NSString* testB = [testA copy];

// 可变拷贝
NSMutableString* testC = [testA mutableCopy];

NSLog(@"%p,%p,%p",testA,testB,testC);
NSLog(@"%@,%@,%@",testA,testB,testC);

[testC replaceOccurrencesOfString:@"内容" withString:@"内容改变" options:NSLiteralSearch range:NSMakeRange(0, testC.length)];

NSLog(@"%p,%p,%p",testA,testB,testC);
NSLog(@"%@,%@,%@",testA,testB,testC);

这段代码输出的信息如下:

0x10966d120,0x10966d120,0x7fb3c8420e30
测试消息内容,测试消息内容,测试消息内容
0x10966d120,0x10966d120,0x7fb3c8420e30
测试消息内容,测试消息内容,测试消息内容改变

由此可以看出,testB实际和testA指向相同的地址,而testC实际是指向了另外的内存。所以也就是OC系统容器类的copy实际是指针拷贝,而mutableCopy则是内容拷贝。
所以对copy而言,新旧指针指向的实际是同一块内存,并不存在内存的拷贝,所以也就无从谈深浅拷贝的问题
mutableCopy则是拷贝了容器自身,返回了一个新的可变数组,指向不同的内存地址而已

全文完

ps:前面两个例子中的c++代码只要稍作转变就可替换成OC代码,此处鉴于篇幅问题,不一一列举。

相关文章

  • 谈谈我理解的拷贝

    这段时间在跟周围开发者讨论的过程中,发现大部分情况下我们很难区分清楚开发中涉及的各种拷贝。比如深拷贝浅拷贝、指针拷...

  • iOS 面试解析|对深浅拷贝的理解

    对深浅拷贝的理解 我们先要理解拷贝的目的:产生一个副本对象,跟源对象互不影响。 深拷贝和浅拷贝的区别 拷贝类型拷贝...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

  • Java深拷贝和浅拷贝

    目录介绍 01.对象拷贝有哪些 02.理解浅拷贝2.1 什么是浅拷贝2.2 实现浅拷贝案例 03.理解深拷贝3.1...

  • 我理解的深拷贝和浅拷贝

    前言 今天一个朋友跟我讨论一下这个深拷贝和浅拷贝的话题,然后感觉自己说的也不是很清楚,所以又特地找了一些资料,让自...

  • iOS之深拷贝与浅拷贝

    深拷贝与浅拷贝是在内存管理中非常重要的概念,理解好深拷贝和浅拷贝也有助于加深对iOS的内存管理的理解。 深拷贝与浅...

  • iOS 深浅拷贝

    iOS深拷贝与浅拷贝的区别 深拷贝与浅拷贝的概念:(我的理解,望不吝赐教) 浅拷贝:只copy一份对象的指针,指向...

  • 简介深浅拷贝

    深浅拷贝 python 直接赋值,浅拷贝和深拷贝 直接赋值 其实就是对象的引用 (可以理解成浅拷贝) 浅拷贝: 拷...

  • 2018-07-29

    1、浅拷贝* 浅拷贝是对一个对象的顶层拷贝* 通俗的理解就是:拷贝了引用,并没有拷贝内容 2、深拷贝* 深拷贝是对...

  • IOS开发之深拷贝与浅拷贝

    拷贝的方式有两种:浅拷贝和深拷贝。 从字面意思理解,浅拷贝,只是拷贝了对象的指针,而不是拷贝对象本身。 深拷贝,是...

网友评论

    本文标题:谈谈我理解的拷贝

    本文链接:https://www.haomeiwen.com/subject/ipacsttx.html