练习13.23
比较上一节练习中你编写的拷贝控制成员和这一节中的代码。确定你理解了你的代码和我们的代码之间的差异(如果有的话)。
解答:
这道题的解答建立在你对13.22题的实现上面,如果个人实现了,可以进行对比。
练习13.24
如果本节中的HasPtr版本未定义析构函数,将会发生什么?如果未定义拷贝构造函数,将会发生什么?
解答:
1. 如果没有定义析构函数的话,会造成内存泄露。因为,成员变量ps是通过new操作在堆上显式分配出的一段内存,需要使用delete显式的去释放。
2. 如果没有定义拷贝构造函数的话,可能会造成二次释放,或使用悬空指针的情况。因为,在合成的赋值运算符中,让不同实例的ps指向同一段内存的起始位置。当其中有一个实例对内存进行释放或其他操作时,别的实例也会受到印象,如果只是修改值之类的操作,影响并不是很大(不至于崩溃);但是,当有释放的操作时,程序很可能会发生崩溃。
练习13.25
假定希望定义StrBlob的类值版本,而且希望继续使用shared_ptr,这样我们StrBlobPtr类就仍能使用指向vector的weak_ptr了。你修改后的类将需要一个拷贝构造函数和一个拷贝赋值运算符,但不需要析构函数。解释拷贝构造函数和拷贝赋值运算符必须要做什么。解释为什么不需要析构函数。
解答:
这里StrBlob使用的是share_ptr智能指针,也就无需像HasPtr那样做出开辟新空间的行为了,需要做的只是直接赋值就可以了,这样只会增加share_ptr的引用数,而不用担心多次释放的问题(只要不适用get,进行对指针的显式释放)。
不需要析构函数是指,直接使用默认的析构函数就可以了,因为shared_ptr是一个类,可以自行管理销毁,不需要显式的去释放。其他的成员变量,都是在栈中创建,在生命周期结束的时候,也就会销毁。所以,默认的析构函数足矣。
练习13.26
对上一题中描述的StrBlob类,编写你自己的版本。
解答:
大概就是这样了
StrBlob& operator=(const StrBlob& ori){
data = ori.data;
return *this;
}
StrBlob(const StrBlob& ori):data(ori.data){}
我的实现是共用指针的方式,这样多个实现拷贝的话,是对同一buffer进行修改,这样有悖常理。
-
这里参考 weixin_38311536 的实现(评论中也有)
StrBlob(const StrBlob& sb) :data(make_shared<vector<string>>(*sb.data)) {} //拷贝构造函数
StrBlob& StrBlob::operator= (const StrBlob& sb) //拷贝复制运算符
{
shared_ptr<vector<string>> p = make_shared<vector<string>>(*(sb.data));
data = p;
return *this;
}