[英]String(const char*) constructor memory leak in string class
So I was trying to implement String class and I got an error saying segmentation fault.所以我试图实现 String class 并且我得到一个错误,说分段错误。 I think there is memory leak in my constructor.我认为我的构造函数中有 memory 泄漏。 Can you please tell me what I am doing wrong?你能告诉我我做错了什么吗? Thank you.谢谢你。
here is the constructor code and I am not permitted to use any standard library functionality.这是构造函数代码,我不允许使用任何标准库功能。
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];
}
};
And also this is my full code:这也是我的完整代码:
#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;
}
The problem with your String(const char* chars)
constructor is on this statement:您的String(const char* chars)
构造函数的问题在于以下语句:
str = new char[len - 1];
You are allocating less memory then you need, so your for
loop is going out of bounds of the allocated memory.您分配的 memory 比您需要的少,因此您的for
循环超出了分配的 memory 的范围。 You need to allocate at least len
number of chars, not len - 1
number of chars:您需要分配至少len
个字符,而不是len - 1
个字符:
str = new char[len];
If you intend str
to be null-terminated, you need to allocate len + 1
number of chars instead, and then insert a null terminator after the loop is finished:如果您打算str
以空值终止,则需要分配len + 1
个字符,然后在循环完成后插入 null 终止符:
str = new char[len + 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = '\0';
You are making a similar mistake in your toChars()
method.您在toChars()
方法中犯了类似的错误。 You are not null-terminating the output, which is required by the operator<<
that you are passing the memory to afterwards:您没有对 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;
}
Note that I removed the noexcept
on toChars()
.请注意,我删除了toChars()
上的noexcept
。 This is because new[]
is not noexcept
, it can throw a std::bad_alloc
exception if it can't allocate memory, which you are not catching.这是因为new[]
不是noexcept
,如果它不能分配 memory,它会抛出一个std::bad_alloc
异常,而你没有捕捉到。 noexcept
means the method doesn't throw
any exception at all, but that is not the case here. noexcept
表示该方法根本不会throw
任何异常,但这里不是这种情况。
There are other problems with your code, too:您的代码也存在其他问题:
Your destructor leaks memory if len
is 0, ie if your Default constructor is called, or your Converting constructor is called with a null/empty string.如果len
为 0,即调用 Default 构造函数,或者使用 null/空字符串调用 Converting 构造函数,则析构函数会泄漏 memory。 If you call new[]
, you need to call delete[]
, regardless of the len
used.如果调用new[]
,则需要调用delete[]
,而不管使用的len
。
Your Copy constructor is not initializing str
or len
if the String
being copied is empty.如果要复制的String
为空,则 Copy 构造函数不会初始化str
或len
。
In main()
, you are not delete[]
'ing the memory that toChars()
returns.在main()
中,您不是delete[]
'ing toChars()
返回的 memory 。
optional for this particular situation, but in general, you are missing a Copy Assignment operator.对于这种特殊情况是可选的,但一般来说,您缺少一个复制分配运算符。 And, since you are clearly using C++11 or later, you should also add a Move constructor and a Move Assignment operator as well.而且,由于您显然使用的是 C++11 或更高版本,您还应该添加一个移动构造函数和一个移动赋值运算符。 See the Rule of 3/5/0 .请参阅3/5/0 规则。
Try this instead (with no additional library functions added, per request):试试这个(没有添加额外的库函数,每个请求):
#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;
}
Although, a simpler way to implement toChars()
would look like this instead:虽然,实现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;
}
You get crash cause you allocate len - 1 chars new char[len - 1]
, but copy len chars for(int j = 0; j < len; j++)
and do not copy zero-char in the end.您会崩溃,因为您分配 len - 1 chars new char[len - 1]
,但复制 len chars for(int j = 0; j < len; j++)
并且最后不复制零字符。
The first constructor should be第一个构造函数应该是
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;
};
I hope you are able to update the second constructor properly.我希望您能够正确更新第二个构造函数。
The destructor should be析构函数应该是
~String() noexcept{
delete[] str;
}
I hope you are able to fix other issues.我希望您能够解决其他问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.