EC笔记:第二部分:11:在operator=中处理“自我赋值”
已經一年半沒有寫過博客了,最近發現學過的知識還是需要整理一下,為知筆記,要開始收費了以前寫在為知筆記上筆記也會慢慢的轉到博客里。
?
話不多說,進入正題。
?
考慮考慮以下場景:
當某個對象對自身賦值時,會出現什么現象??
例子:
#include <iostream>
class A {
private:
????int *arr;
public:
????A() {
????????arr = new int[256];
????}
????~A() {
????????delete arr;
????}
????const A& operator=(const A &other) {
????????delete arr;????????????????????//清除原來的值
????????arr = new int[256];????????????//重新分配內存
????????std::memcpy(arr, other.arr, 256 * sizeof(int));????//賦值
????????return *this;
????}
};
?
?
在這段代碼中,類A管理了256個整數的數組,當發生賦值操作時,對象先將自身管理的內存區釋放,然后重新分配內存并且賦值(這里可以直接進行內存拷貝,為了演示,做了刪除并重新分配操作,假設這里是個vector,想象一下^_^)。這個實現在應對大多數情況是沒有問題的。如:
?
int main() {
????A a;
????A b;
????a = b;
}
這樣完全沒有問題。但是,假設出現以下場景:
int main() {
????A a;
????A &b = a;
?
????//若干操作
?
????a = b;
}
?
a和b表示的是同一個對象,那么在重新分配內存之前,就會將arr(a和b是同一個)指向的內存區域釋放。然后在做memcpy的時候程序就會崩潰(引用了已釋放的內存區域)。
?
重新對class A的operator=實現:
#include <iostream>
class A {
private:
????int *arr;
public:
????A() {
????????arr = new int[256];
????}
????~A() {
????????delete arr;
????}
????const A& operator=(const A &other) {
????????if(this == &other)
????????????return *this;
????????delete arr;????????????????????//清除原來的值
????????arr = new int[256];????????????//重新分配內存
????????std::memcpy(arr, other.arr, 256 * sizeof(int));????//賦值
????????return *this;
????}
};
?
改進后,判斷當前如果賦值和被賦值的是同一個對象,就直接返回,可以避免釋放掉同一塊內存。
?
這段代碼雖然可以避免賦值上的問題,但是存在"異常安全性"的問題:試想,假設在new的時候拋出了一個異常(假設內存不足),那么,a在處理異常時,arr的狀態就已經發生變化了。
?
另外,書中介紹了另一種避免賦值的時候釋放掉有用內存的代碼:
#include <iostream>
class A {
private:
????int *arr;
public:
????A() {
????????arr = new int[256];
????}
????~A() {
????????delete arr;
????}
????const A& operator=(const A &other) {
????????int *old_arr = arr;
????????arr = new int[256];
????????std::memcpy(arr, other.arr, 256 * sizeof(int));
????????delete old_arr;
????????return *this;
????}
};
?
這段代碼中,先對原有的arr做一個備份,然后使用other對新分配的內存進行更新,最后釋放掉原來arr指向的內存區域。
即使沒有"證同測試",這段代碼也能正常工作,因為釋放動作在賦值動作之后,這是后就真的存在兩個副本了(如果*this和other指向不同的值,就是3個副本)。但是,這段代碼顯然在拋開"異常安全性"后在效率上比上面那段代碼的效率低(即使兩個對象指向同一內存,也要從新分配內存,并重新賦值)。所以,如果關心效率的話,應該在最前面增加"證同測試"。如下:
#include <iostream>
class A {
private:
????int *arr;
public:
????A() {
????????arr = new int[256];
????}
????~A() {
????????delete arr;
????}
????const A& operator=(const A &other) {
????????if (this==&other)
????????????return *this;
????????int *old_arr = arr;
????????arr = new int[256];
????????std::memcpy(arr, other.arr, 256 * sizeof(int));
????????delete old_arr;
????????return *this;
????}
};
?
至此,一份"異常安全的"且"效率優秀的"operator=操作符就完成了
?
請記住:
轉載于:https://www.cnblogs.com/SkyFireITDIY/p/6201174.html
總結
以上是生活随笔為你收集整理的EC笔记:第二部分:11:在operator=中处理“自我赋值”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个人日记2016年12月19日21:31
- 下一篇: 1.Jenkins 在windows下的