[英]Assignment overloading: why does using the same object cause problems in the program?
假設我們有以下內容:
class StringClass
{
public:
...
void someProcessing( );
...
StringClass& operator=(const StringClass& rtSide);
...
private:
char *a;//Dynamic array for characters in the string
int capacity;//size of dynamic array a
int length;//Number of characters in a
};
StringClass& StringClass::operator=(const StringClass& rtSide)
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
我的問題是:當我們嘗試向其自身分配對象時,這種重載賦值運算符的實現為什么會引起問題?
StringClass s;
s = s;
我正在閱讀的教科書(Absolute C ++)說, delete [] a;
后delete [] a;
“然后指針sa是未定義的。賦值運算符破壞了對象s,並且該程序的運行可能已損壞。”
為什么運算符損壞了s? 如果刪除后立即重新初始化sa,為什么會在程序中引起這樣的問題,我們必須將函數重新定義為:
StringClass& StringClass::operator=(const StringClass& rtSide)
{
if (this == &rtSide)
//if the right side is the same as the left side
{
return *this;
}
else
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
}
如果您要為其本身分配一個對象,則a
和rt.a
指向同一字符串,因此當您delete [] a
您將同時刪除a
和rt.a
指向的內容; 那么您確實要重新分配它,但是要在循環中(自己復制)的數據已在delete
丟失。
現在,在循環中,您將只復制new
自身返回的內存中的所有垃圾。
順便說一句,即使使用了自賦值檢查的“安全網”,賦值運算符也不是完全可以的(例如,它不是異常安全的); 定義“三巨頭”(復制構造函數,賦值運算符,析構函數)的“安全”方法是使用“ 復制和交換習慣用法 ”。
如果您進行自我分配,請先通過LHS參數釋放( delete
)字符串,然后再通過RHS參數將其復制到新分配的空間。 這不是幸福的秘訣。 這是未定義的行為,可能會發生任何事情。 崩潰是合理的; 如果您真的很不幸,它可能會起作用。
考慮一下當您位於損壞的operator=
內部時rtSide.a
的值是什么。
與this->a
相同,您剛剛破壞的值。 訪問非擁有的內存是未定義的行為,因此訪問this-> a是未定義的行為(因為您剛剛釋放了它)。
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //Invalid when this->a == rtSide.a
//because rtSide.a is no longer owned by your program.
如果您確實要執行此操作,則必須先復制的副本,然后再刪除它:
char* ca;
if (this == &rtSide) {
ca = copy of rtSide.a or this->a;
} else {
ca = rtSide.a;
}
//Do your assigning and whatnot
if (this == &rtSide) {
delete[] ca;
}
顯然,不做任何事而不是使所有實例的臨時副本都擁有成員會更有效。 與int x = 5; int y = x; x = y;
概念相同int x = 5; int y = x; x = y;
int x = 5; int y = x; x = y;
這是因為您首先刪除了指針delete [] a;
然后稍后嘗試從已刪除的位置進行復制:
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
請記住,它是您要從中復制的位置,您已經將其刪除。 因此,錯誤!
您發布的以后的代碼通過檢查自賦值作為單獨的案例來解決此問題。
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
這就是為什么。 這樣想:
您刪除任何指向的點,然后分配新的內存塊。 新的內存塊包含垃圾,這些垃圾將成為您的新數據。 不要被a[i] = rtSide.a[i];
的循環所迷惑a[i] = rtSide.a[i];
只會將垃圾復制到自身上。
請記住, this
和rtSide
都將您引向同一個對象。 使用this
修改對象時, rtSide
引用的對象將被修改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.