你的析構函數失敗:
三個規則(也被稱爲三巨頭或法的三巨頭)是拇指在C++(之前的C++ 11的規則)聲稱,如果一個類定義了一個(或多個)以下的,應該可能顯式定義所有三個:
類是缺少接受test
對象作爲輸入一個拷貝構造函數。你有一個轉換構造函數接受char*
作爲輸入,但如果該輸入超過9個字符比在複製字符時垃圾回收周圍的內存。
您的班級是缺少一個拷貝賦值操作符,它接受一個test
對象作爲輸入。你有一個將接受一個char*
作爲輸入賦值運算符,但它正在所有權是char*
,而不是把一個複製的字符數據的的,並且是漏水以前分配的緩衝區string
。更糟糕的是,它返回正在修改的test
對象的副本,而不是返回參考的對象,並且該副本不會因爲你缺少拷貝構造函數的正常工作。所以最終會有多個test
對象指向內存中相同的string
緩衝區,所以您將在同一內存中多次使用調用delete[]
的析構函數。
此外,您的operator+
也被錯誤地實施。它返回一個新的test
對象,但它沒有分配佔兩個源字符串總長度的新內存。您只需將右側的test
對象中的字符數據直接複製到左側的test
對象的char*
字符串中,而無需首先展開它。所以你在搗毀周圍的記憶。這個operator+
應該返回一個新的test
對象,它是連接在一起的輸入字符串的副本,根本不修改任何源字符串。
嘗試一些更喜歡這個:
class test
{
public:
// default constructor
test()
: string(0)
{
}
// copy constructor
test(const test &src)
: string(new char[src.starlen()+1])
{
strcpy(string, src.string);
}
// converting constructor
test(const char* src)
: string(new char[strlen(src)+1])
{
strcpy(string, src);
}
// destructor
~test()
{
delete[] string;
}
// copy assignment operator
test& operator=(const test &rhs)
{
if (&rhs != this)
std::swap(string, test(rhs).string);
return *this;
}
// converting assignment operator
test& operator=(const char *rhs)
{
std::swap(string, test(rhs).string);
return *this;
}
int starlen() const
{
return strlen(string);
}
test operator+(const test& rhs) const
{
int a = starlen();
int b = rhs.starlen();
test ret;
ret.string = new char[a+b+1];
strcpy(ret.string, string);
strcpy(ret.string+a, rhs.string);
return ret;
}
void printit() const
{
std::cout << string;
}
private:
char* string;
};
int main()
{
test t1("book");
test t2("shelf");
test t3;
t3 = t1 + t2;
cout << t3.starlen() << endl;
t3.printit();
return 0;
}
如果您正在使用C++ 11或更高版本,你也應該遵循Rule of Five還有:
隨着C的來臨+ +11三條規則可以擴展爲五條規則,因爲C++ 11實現了移動語義,允許目標對象從臨時對象中獲取(或竊取)數據。以下示例還顯示了新的移動成員:移動構造函數和移動賦值運算符。因此,對於五個規則,我們有以下特殊成員:
- 析構函數
- 拷貝構造函數
- 轉移構造
- 拷貝賦值運算符
- 移動賦值運算符
class test
{
public:
// default constructor
test()
: string(0)
{
}
// copy constructor
test(const test &src)
: string(new char[src.starlen()+1])
{
strcpy(string, src.string);
}
// converting constructor
test(const char* src)
: string(new char[strlen(src)+1])
{
strcpy(string, src);
}
// move constructor
test(test &&src)
: string(0)
{
std::swap(string, src.string);
}
// destructor
~test()
{
delete[] string;
}
// copy assignment operator
test& operator=(const test &rhs)
{
if (&rhs != this)
std::swap(string, test(rhs).string);
return *this;
}
// converting assignment operator
test& operator=(const char *rhs)
{
std::swap(string, test(rhs).string);
return *this;
}
// move assignment operator
test& operator=(test &&rhs)
{
std::swap(string, rhs.string);
return *this;
}
int starlen() const
{
return strlen(string);
}
test operator+(const test& rhs) const
{
int a = starlen();
int b = rhs.starlen();
test ret;
ret.string = new char[a+b+1];
strcpy(ret.string, string);
strcpy(ret.string+a, rhs.string);
return ret;
}
void printit() const
{
std::cout << string;
}
private:
char* string;
};
這就是說,這可能只是一個如何編寫自定義字符串類的學習練習。但是,C++標準定義了std::string
類,您應該使用它。如果你想自己的類,你可以委託給std::string
,讓編譯器和STL做繁重的工作適合你:
class test
{
public:
// default constructor
test()
{
}
// copy constructor
test(const test &src)
: str(src.str)
{
}
// converting constructor
test(const std::string &src)
: str(src)
{
}
// move constructor
test(test &&src)
: str(std::move(src.str))
{
}
int starlen() const
{
return str.length();
}
test operator+(const test& rhs) const
{
return str + rhs.str;
}
void printit() const
{
std::cout << str;
}
private:
std::string str;
};
請刪除代碼中所有多餘的空行。 –
如果有人使用沒有任何參數的構造函數會怎麼樣?那麼你會'刪除[] 0',那肯定會出錯。另外,「垃圾」是什麼意思?這個問題沒有很好解釋。 –
你嘗試過使用調試器嗎? –