本帖屬不定時連載貼,以試卷的形式提出一個比較基礎的問題供大家思考討論,問題的解析將在下一更新貼中一併給出,這樣做是希望還不清楚問題的朋友有自己思考和討論的時間,希望大家能從這些帖子中有所收穫。
貼中問題屬我在學習CC++過程中遇到的一些語法或者比較隱晦的程式問題,其中有自己的總結,也不乏網路上搜尋到的經典解析,在此分享給大家,希望能起到拋磚引玉的作用
我已認真檢查過自己的帖子,但難免有疏忽,如大家在閱讀過程中仍發現有問題,請及時通知,我會及時更正,以免誤導大家,萬分感謝^_^
【No.16 異常的直接插入排序】
由於連載形式,每帖第二部分都配有上一問題的解答。為了保持帖子的針對性和一致性,此貼僅供交流討論本次問題,若大家對上一問題有任何疑問,請通過解答末尾的傳送連結前往該問題貼回覆討論
[問題No.16]
下面的直接插入排序邏輯沒有問題,但為什麼無法正確執行呢?
程式碼:
void insertSort(int *arr, const size_t arrLength){
for(size_t i=1; i<arrLength; ++i){
int elemToInsert = arr;
size_t j = 0;
for(j=i-1; j>=0; --j){
if(arr[j] > elemToInsert)
arr[j+1] = arr[j];
else
break;
}
arr[j+1] = elemToInsert;
}
}
本主題主要是向大家提出物件“自賦值”的問題,以引起大家的重視。這是個經典的問題,我們在編寫賦值操作符時,既要具有自賦值安全性(即自賦值不應該改變原物件的狀態),也應該具有異常安全性。下面的程式碼對這一問題進行了簡要闡釋,希望尚不知道的午飯引起重視。
程式碼:
#include<iostream>
#include<string>
using std::cout;
using std::endl;
using std::string;
#define WITHOUT_IDENTITY_TEST //沒有對自賦值做檢測
//#define IDENTITY_TEST //有自賦值檢測,但沒有異常安全
//#define SAVING_ORIGIN_POINTER //提供異常安全,並順帶提供了自賦值檢測
//#define COPY_AND_SWAP //一種被稱為copy and swap的技術提供異常安全,並順帶提供自賦值檢測
class Foo
{
public:
Foo(const string str) : _str(new string(str)){ }
Foo(const Foo &foo){ _str = new string(*foo._str); }
~Foo(void){ delete _str; }
#ifdef WITHOUT_IDENTITY_TEST
//沒有對自賦值做檢測
Foo& operator =(const Foo &foo){
delete _str;
_str = new string(*foo._str);
return *this;
}
#endif
#ifdef IDENTITY_TEST
//有自賦值檢測,但沒有異常安全
Foo& operator =(const Foo &foo){
if(this == &foo)
return *this;
delete _str;
_str = new string(*foo._str);
return *this;
}
#endif
#ifdef SAVING_ORIGIN_POINTER
//提供異常安全,並順帶提供了自賦值檢測
Foo& operator =(const Foo &foo){
string *original = _str;
_str = new string(*foo._str);
return *this;
}
#endif
#ifdef COPY_AND_SWAP
//一種被稱為copy and swap的技術提供異常安全,並順帶提供自賦值檢測
Foo& operator =(const Foo &foo){
Foo temp(foo);
_swap(temp);
return *this;
}
#endif
const string& getStr(void) const { return *_str; }
private:
void _swap(Foo &foo){
string temp = *_str;
*_str = *foo._str;
*foo._str = temp;
}
string *_str;
};
int main(int argc, char **argv)
{
Foo f1("first"), f2("second");
cout<<"f1 = "<<f1.getStr()<<" f2 = "<<f2.getStr()<<endl;
f1 = f2;
cout<<"f1 = "<<f1.getStr()<<" f2 = "<<f2.getStr()<<endl;
f1 = f1;
cout<<"f1 = "<<f1.getStr()<<" f2 = "<<f2.getStr()<<endl;
return EXIT_SUCCESS;
}