[英]String(const char*) constructor memory leak in string class
所以我試圖實現 String class 並且我得到一個錯誤,說分段錯誤。 我認為我的構造函數中有 memory 泄漏。 你能告訴我我做錯了什么嗎? 謝謝你。
這是構造函數代碼,我不允許使用任何標准庫功能。
String(const char* chars){
int i = 0;
if(chars){
while(chars[i]){
i++;
}
}
len = i;
str = new char[len - 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
};
這也是我的完整代碼:
#include <iostream>
using namespace std;
class String{
public:
char* str;
int len;
String(){
str = new char[0];
len = 0;
};
String(const char* chars){
int i = 0;
if(chars){
while(chars[i]){
i++;
}
}
len = i;
str = new char[len - 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
};
String(const String& s){
if(s.isEmpty() == false){
len = s.len;
str = new char[len];
for(int i = 0; i < len; i++){
str[i] = s.str[i];
}
}
};
~String() noexcept{
if(len > 0)
delete[] str;
};
bool isEmpty() const noexcept{
if(len == 0){
return true;
}
else{
return false;
}
}
unsigned int length() const noexcept{
return len;
}
const char* toChars() const noexcept{
char* temp = new char[len];
int c = 0;
while(temp[c] != '\0'){
temp[c] = str[c];
c++;
}
return temp;
}
};
int main()
{
const char* chars = "Boo is snoring";
String s;
String t{chars};
cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl;
return 0;
}
您的String(const char* chars)
構造函數的問題在於以下語句:
str = new char[len - 1];
您分配的 memory 比您需要的少,因此您的for
循環超出了分配的 memory 的范圍。 您需要分配至少len
個字符,而不是len - 1
個字符:
str = new char[len];
如果您打算str
以空值終止,則需要分配len + 1
個字符,然后在循環完成后插入 null 終止符:
str = new char[len + 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = '\0';
您在toChars()
方法中犯了類似的錯誤。 您沒有對 output 進行空終止,這是operator<<
要求您將 memory 傳遞給之后的:
const char* toChars() const {
char* temp = new char[len + 1];
for(int c = 0; c < len; ++c){
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
請注意,我刪除了toChars()
上的noexcept
。 這是因為new[]
不是noexcept
,如果它不能分配 memory,它會拋出一個std::bad_alloc
異常,而你沒有捕捉到。 noexcept
表示該方法根本不會throw
任何異常,但這里不是這種情況。
您的代碼也存在其他問題:
如果len
為 0,即調用 Default 構造函數,或者使用 null/空字符串調用 Converting 構造函數,則析構函數會泄漏 memory。 如果調用new[]
,則需要調用delete[]
,而不管使用的len
。
如果要復制的String
為空,則 Copy 構造函數不會初始化str
或len
。
在main()
中,您不是delete[]
'ing toChars()
返回的 memory 。
對於這種特殊情況是可選的,但一般來說,您缺少一個復制分配運算符。 而且,由於您顯然使用的是 C++11 或更高版本,您還應該添加一個移動構造函數和一個移動賦值運算符。 請參閱3/5/0 規則。
試試這個(沒有添加額外的庫函數,每個請求):
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const {
char* temp = new char[len + 1];
for(unsigned int c = 0; c < len; ++c) {
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
};
int main()
{
String t{"Boo is snoring"};
const char *chars = t.toChars();
cout << "t.len : " << t.length() << endl << "toChar() : " << chars << endl;
delete[] chars;
return 0;
}
雖然,實現toChars()
的更簡單方法看起來像這樣:
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len + 1];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
str[len] = '\0';
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len + 1];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
str[len] = '\0';
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const noexcept {
return str ? str : "";
}
};
int main()
{
String t{"Boo is snoring"};
cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl;
return 0;
}
您會崩潰,因為您分配 len - 1 chars new char[len - 1]
,但復制 len chars for(int j = 0; j < len; j++)
並且最后不復制零字符。
第一個構造函數應該是
String(const char* chars) {
len = 0;
if (chars) {
while (chars[len])
len++;
}
str = new char[len + 1];
for (int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = 0;
};
我希望您能夠正確更新第二個構造函數。
析構函數應該是
~String() noexcept{
delete[] str;
}
我希望您能夠解決其他問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.