可变容器的深浅拷贝问题

本文探讨了Objective-C中深拷贝和浅拷贝的概念,通过实例展示了`copy`和`mutableCopy`在字典操作中的行为。分析了不同拷贝方式对容器对象和其内部值的影响,以及`strong`属性在对象引用中的作用。当可变字典被拷贝后,即使原字典修改,拷贝后的容器对象仍然能保持其原始状态,但容器内的值并未进行深拷贝,仍受原容器影响。
摘要由CSDN通过智能技术生成

结论

  1. copy自不可变、或者mutableCopy自可变、不可变的容器,都是容器对象的深拷贝
  2. 上面的深拷贝只是容器对象,容器里的值还是浅拷贝的
  • 使用copy修饰property、直接copy 可变字典两种情况,查看容器对象和容器里值的地址情况:
//TestObject.h
#import <Foundation/Foundation.h>

@interface TestObject : NSObject

@property(nonatomic, copy) NSDictionary *dic;
@property(nonatomic, strong) NSDictionary *testDic;

@end
#import "TestObject.h"


int main(int argc, char * argv[]) {
    @autoreleasepool { 
        NSMutableDictionary *mutableDic = [[NSMutableDictionary alloc] init];
        mutableDic[@"Name"] = @"kailinWang";
        mutableDic[@"Age"] = @"18";

		NSDictionary *copyDic = [mutableDic copy];
		TestObject *obj = [[TestObject alloc] init];
        obj.dic = mutableDic;
        obj.testDic = mutableDic;
        
        NSLog(@"不可变的地址是%p,copy属性的地址是%p, strong属性的地址是%p, copyDic的地址是%p",mutableDic, obj.dic, obj.testDic, copyDic);
        NSLog(@"不可变Name地址是%p,copy属性的Name地址%p,strong属性的Name地址是%p, copyDic的Name的地址是%p",mutableDic[@"Name"],obj.dic[@"Name"],obj.testDic[@"Name"],copyDic[@"Name"]);
        [mutableDic removeObjectForKey:@"Name"];
        NSLog(@"不可变Name地址是%p,copy属性的Name地址%p,strong属性的Name地址是%p, copyDic的Name的地址是%p",mutableDic[@"Name"],obj.dic[@"Name"],obj.testDic[@"Name"],copyDic[@"Name"]);
    }
}
  • 运行结果如下:

在这里插入图片描述

  • 使用strong修饰的property的容器对象地址和原可变容器对象一致,均为0x600001949e60,使用copy修饰的property以及copy的临时NSDictionary容器对象都有一个新的地址
  • 容器里的对象不会因为原不可变字典remove就释放掉,因为还有两处copy的,而使用strong修饰的testDic是指针拷贝,因此remove后也访问不到了
  • 其他两处copy的仍可以继续访问key为@"Name"的对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,`std::vector`是一种动态数组容器,用于存储同型的元素,并支持自动增长功能。关于`vector`的拷贝操作分为浅拷贝拷贝两种。 ### 浅拷贝 浅拷贝涉及到复制指向原始数据的数据结构(如指针),即创建一个新的对象,将原来的对象的内存地址赋值给新对象。这种方式只复制了容器指向的数据的位置,而没有实际移动或复制数据本身。因此,在浅拷贝的情况下,两个`vector`实例之间共享相同的内部数据缓冲区,这可能导致修改其中一个实例会同时影响另一个实例的问题。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> original = {1, 2, 3}; std::vector<int> shallowCopy(&original, &original[original.size()]); // 修改原vector的第二个元素 original = 4; // 打印浅拷贝的结果 for (const auto& elem : shallowCopy) { std::cout << elem << " "; } // 输出结果应为 1 4 3 ,说明浅拷贝后的vector也跟着改变了 } ``` ### 拷贝 拷贝则涉及到复制容器内的所有数据成员。这意味着创建一个新的独立内存区域并填充相同的内容,而不是简单地引用现有的内存位置。在这种情况下,每个`vector`实例都拥有自己的数据副本,所以对其中一个实例的修改不会影响到其他实例。 ```cpp #include <iostream> #include <vector> int main() { std::vector<int> original = {1, 2, 3}; std::vector<int> deepCopy(original); // 使用构造函数或copy构造函数进行拷贝 // 修改原vector的第一个元素 original = -1; // 打印拷贝的结果 for (const auto& elem : deepCopy) { std::cout << elem << " "; } // 输出结果应为 1 2 3 ,说明拷贝后的vector保持不变 } ``` ### 相关问题: 1. **如何手动实现`vector`的拷贝?** 可以通过构造函数的方式或者使用`std::vector::operator=(const vector&)`进行拷贝,但是需要特别注意的是,使用这种拷贝赋值符可能会引发效率低下或资源泄露问题,因为它们通常默认实现为浅拷贝,除非在内部进行了特殊的优化。 2. **何时应该使用拷贝而非浅拷贝?** 当处理不可变的数据或希望确保各个实例之间的数据独立时,应使用拷贝。例如,当你构建的对象包含昂贵的计算生成的资源时,避免浅拷贝可以节省内存和计算资源。 3. **拷贝和浅拷贝在性能上有何差异?** 拷贝通常比浅拷贝更耗时和消耗更多内存,因为它涉及复制整个数据集合。然而,从维护数据一致性以及防止副作用的角度考虑,其额外的成本可能是值得的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值