之前在文章类内裸指针的使用方法中提到裸指针涉及到浅拷贝,导致崩溃,解决方案中 提到可以使用共享指针杜绝浅拷贝。今日结合python代码再次剖析其原因。
python
首先我们看一段python代码
a=[1,2,3,[4,5,6]]
b=a.copy()
print(a)
print(b)
print(f"{***************************************}")
a.append(11)
print(f"{a}\ta address is {id(a)}")
print(f"{b}\t\tb address is {id(b)}")
print(f"{***************************************}")
a[3].append(21)
print(f"{a[3]}\ta[3] address is {id(a[3])}")
print(f"{b[3]}\tb[3] address is {id(b[3])}")
'''
输出结果如下:
[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5, 6]]
***************************************
[1, 2, 3, [4, 5, 6], 11] a address is 2247516418944
[1, 2, 3, [4, 5, 6]] b address is 2247516438848
***************************************
[4, 5, 6, 21] a[3] address is 2247516452288
[4, 5, 6, 21] b[3] address is 2247516452288
'''
上述代码:列表a内含一个列表,通过列表的copy方法赋值给了列表b,通过a b的地址可知,a和b是两个不同的对象,其数值虽然引用自相同的地址,但是各自独立持有;因此在给a增加数值型变量11时,仅a被追加了11,b并未被追加,即两者并未同步;但是对于列表中的列表a[3]追加数值型变量21时,两者同步变化.
由上可知,针对于只有数值类型的变量不必考虑深拷贝和浅拷贝,当其内部含有二级列表或其他的内建集合类型时需要考虑使用深拷贝,杜绝浅拷贝产生的问题。
C++
再次回归到C++来,且看如下的代码,
class People
{
public:
int age{20};
char* name{nullptr};
People(intage_, std::stringname_):age{age_}
{
name = (char*) malloc(sizeof(name_)+1);
memcpy(name,name_.c_str(),sizeof(name_));
name[sizeof(name_)]='\0';
}
~People()
{
if (name)
{
free(name);
name=nullptr;
}
}
};
void test_shallow_copy()
{
People a{ 30,"dany" };
People b = a;
printf("a age address %p, b age address %p\n", &a.age, &b.age);
printf("a name address %p, b name address %p\n", a.name, b.name);
}
/*
a age address 0000003916AFF7B8, b age address 0000003916AFF7E8
a name address 0000021D54421620, b name address 0000021D54421620
*/
从以上输出结果可知,a和b对象的数值型变量age地址是不同的;反观指针型变量name的地址却是相同的。
总结
结合C++和python代码可知,如果类内只有数值型变量,无需考虑深拷贝或浅拷贝,但是如果C++类内会存在指针类型、python的数据结构内部存在二级列表等数值型集合时,需要考虑使用深拷贝,杜绝浅拷贝现象。
这也就是C++类内使用智能指针(数值型对象)代替裸指针的原因。