Jun 28, 2015 at 5:06pm UTC
So I wrote the code for the string class but I know it can be improved. Especially for the += operator.
Here it is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
#include <iostream>
#include <cassert>
using namespace std;
class String {
int size;
char * buffer;
public :
String();
String(const String &);
String(const char *);
~String();
int length() const ;
char & operator [] (unsigned int );
void operator =(const String&);
void operator += (const String&);
// other methods
friend bool operator ==(const String &, const String &);
friend bool operator <=(const String &, const String &);
friend bool operator <(const String &, const String &);
friend ostream & operator <<(ostream &, const String &);
};
String::String()
{
buffer = nullptr ;
size = 0;
}
String::String(const String&s)
{
size = s.size;
buffer = new char [size];
for (int i = 0; i < size; i++){
buffer[i] = s.buffer[i];
}
}
String::String(const char *p)
{
int i = 0;
const char * t = p;
while (*p++)
{
i++;
}
buffer = new char [i];
int j = 0;
for (j;*t;t++,j++)
{
buffer[j] = *t;
}
size = j;
}
String::~String()
{
delete [] buffer;
}
int String::length() const
{
if (buffer == nullptr )
{
return 0;
}
else
{
return size;
}
}
char & String::operator [] (unsigned int x)
{
return buffer[x];
}
void String::operator =(const String&s)
{
size = s.size;
buffer = new char [size];
for (int i = 0; i < s.length();i++)
{
buffer[i] = s.buffer[i];
}
}
ostream & operator <<(ostream &os, const String &s)
{
for (int i = 0; i < s.size; i++)
{
os << s.buffer[i];
}
return os;
}
bool operator ==(const String & s, const String & t)
{
if (s.length() != t.length())
{
return false ;
}
else
{
for (int i = 0; i < s.length(); i++)
{
if (s.buffer[i] != t.buffer[i])
{
return false ;
}
}
}
return true ;
}
void String::operator += (const String& s)
{
char * temp = new char [size];
int t = length();
for (int i = 0; i < length(); i++)
{
temp[i] = buffer[i];
}
int tsize = size + s.size;
buffer = new char [tsize];
for (int i = 0; i < length(); i++)
{
buffer[i] = temp[i];
}
for (int i = t, j = 0; j < s.length(); i++,j++)
{
buffer[i] = s.buffer[j];
}
size+=s.size;
delete [] temp;
}
int main()
{
String s1; // s1 == ""
assert(s1.length() == 0);
String s2("hi" ); // s2 == "hi"
assert(s2.length() == 2);
String s3(s2); // s3 == "hi"
assert(s3.length() == 2);
assert(s3[0] == 'h' );
assert(s3[1] == 'i' );
s1 = s2; // s1 == "hi"
assert(s1 == s2);
s3 = "bye" ; // s3 == "bye"
assert(s3.length() == 3);
assert(s3[0] == 'b' );
assert(s3[1] == 'y' );
assert(s3[2] == 'e' );
s1 += "re" ; // s1 == "hire"
assert(s1 == "hire" );
s1 += "d" ; // s1 == "hired"
assert(not (s1 == "hire" ));
cout << "SUCCESS" << endl;
}
Last edited on Jun 28, 2015 at 9:55pm UTC
Jun 28, 2015 at 5:35pm UTC
String::operator+=() leaks memory.
Jun 28, 2015 at 8:54pm UTC
Thanks, I fixed that I think.
Jun 28, 2015 at 9:23pm UTC
@ OP if you use new [] you must use delete [] and if you use new you must use delete. So in the case of your += overload, you use new [] and then use delete which causes the leak.
Jun 28, 2015 at 9:37pm UTC
I would have preferred to let OP figure it out.
Anyway, there's another leak besides what giblit said.
Jun 28, 2015 at 9:59pm UTC
Thanks giblit. And helios, I don't think I see it.
I know I create a few arrays in there. Like where my String::operator=() is. But I thought the destructor took care of that one.
Isn't the L-value of that buffer attached to the string which is being set to equal the one being passed in the argument?
Last edited on Jun 28, 2015 at 10:01pm UTC
Jun 28, 2015 at 11:15pm UTC
But I thought the destructor took care of that one.
Have you considered carefully what happens when you assign a new value to an existing string?
1 2 3
String test("Hello" );
test = "Hello leak!" ;
and you should also think about
1 2 3
String test("Hello" );
test = test;
Andy
PS As the code stands there are two leaks.
Last edited on Jun 28, 2015 at 11:56pm UTC
Jun 29, 2015 at 12:01am UTC
<removed post as not as sure as I orig thought...>
Last edited on Jun 29, 2015 at 1:21am UTC
Jun 29, 2015 at 12:19am UTC
Does it create a memory leak because it never releases the memory that holds "hello" and allocates new memory for "Hello leak"?
Yep!
Andy
Last edited on Jun 29, 2015 at 12:20am UTC
Jun 29, 2015 at 12:25am UTC
Awesome! Now I've updated my code but I am curious if I still have leaks here. I believe I fixed it but I may have overlooked something.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
#include <iostream>
#include <cassert>
using namespace std;
class String {
int size;
char * buffer;
public :
String();
String(const String &);
String(const char *);
~String();
int length() const ;
char & operator [] (unsigned int );
void operator =(const String&);
void operator += (const String&);
// other methods
friend bool operator ==(const String &, const String &);
friend bool operator <=(const String &, const String &);
friend bool operator <(const String &, const String &);
friend ostream & operator <<(ostream &, const String &);
};
String::String()
{
buffer = nullptr ;
size = 0;
}
String::String(const String&s)
{
size = s.size;
buffer = new char [size];
for (int i = 0; i < size; i++){
buffer[i] = s.buffer[i];
}
}
String::String(const char *p)
{
int i = 0;
const char * t = p;
while (*p++)
{
i++;
}
buffer = new char [i];
int j = 0;
for (j;*t;t++,j++)
{
buffer[j] = *t;
}
size = j;
}
String::~String()
{
delete [] buffer;
}
int String::length() const
{
if (buffer == nullptr )
{
return 0;
}
else
{
return size;
}
}
char & String::operator [] (unsigned int x)
{
return buffer[x];
}
void String::operator =(const String&s)
{
delete [] buffer;
size = s.size;
buffer = new char [size];
for (int i = 0; i < s.length();i++)
{
buffer[i] = s.buffer[i];
}
}
ostream & operator <<(ostream &os, const String &s)
{
for (int i = 0; i < s.size; i++)
{
os << s.buffer[i];
}
return os;
}
bool operator ==(const String & s, const String & t)
{
if (s.length() != t.length())
{
return false ;
}
else
{
for (int i = 0; i < s.length(); i++)
{
if (s.buffer[i] != t.buffer[i])
{
return false ;
}
}
}
return true ;
}
void String::operator += (const String& s)
{
char * temp = new char [size];
int t = length();
for (int i = 0; i < length(); i++)
{
temp[i] = buffer[i];
}
int tsize = size + s.size;
buffer = new char [tsize];
for (int i = 0; i < length(); i++)
{
buffer[i] = temp[i];
}
for (int i = t, j = 0; j < s.length(); i++,j++)
{
buffer[i] = s.buffer[j];
}
size+=s.size;
delete [] temp;
}
int main()
{
String s1; // s1 == ""
assert(s1.length() == 0);
String s2("hi" ); // s2 == "hi"
assert(s2.length() == 2);
String s3(s2); // s3 == "hi"
assert(s3.length() == 2);
assert(s3[0] == 'h' );
assert(s3[1] == 'i' );
s1 = s2; // s1 == "hi"
assert(s1 == s2);
s3 = "bye" ; // s3 == "bye"
assert(s3.length() == 3);
assert(s3[0] == 'b' );
assert(s3[1] == 'y' );
assert(s3[2] == 'e' );
s1 += "re" ; // s1 == "hire"
assert(s1 == "hire" );
s1 += "d" ; // s1 == "hired"
assert(not (s1 == "hire" ));
cout << "SUCCESS" << endl;
}
Last edited on Jun 29, 2015 at 12:26am UTC
Jun 29, 2015 at 12:41am UTC
Yes, there's still one other leak.
Also, I just noticed possible illegal accesses in String::String(const String&) and String::operator=(const String&), and two more in String::operator+=().
Jun 29, 2015 at 12:55am UTC
You're missing test cases:
1. copy constructor from empty object (one which is default constructed)
2. operator= with empty object
3. operator= with same object
4. operator+= with empty object
5. operator+= with same object
And more!
(It might help to split out test cases into separate functions?)
Andy
Last edited on Jun 29, 2015 at 12:56am UTC
Jun 29, 2015 at 2:16am UTC
I'm not familiar with illegal accesses.
And thanks for the additional test cases Andy. I am seeing my implementation fail as I add some of those in.
#3 seems to be causing a crash as it is.
Jun 29, 2015 at 9:24am UTC
I'm not familiar with illegal accesses.
This is what prompted me to suggest the additional test cases.
For example...
32 33 34 35 36 37 38 39
String::String(const String&s)
{
size = s.size;
buffer = new char [size];
for (int i = 0; i < size; i++){
buffer[i] = s.buffer[i]; // what memory are you accessing here if s is empty??
}
}
#3 seems to be causing a crash as it is.
Hopefully this should become clear if you think about what's happening to the buffer?
Andy
Last edited on Jun 29, 2015 at 9:33am UTC
Jun 29, 2015 at 4:00pm UTC
So I believe I have to make a check to see if the buffer is empty? For the illegal accesses.
And how would I handle this? It fixes the problem but I'm not sure if I'm creating another problem by doing this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
void String::operator =(const String&s)
{
if (buffer == s.buffer)
{
//do nothing
}
else {
delete [] buffer;
size = s.size;
buffer = new char [size];
for (int i = 0; i < s.length();i++)
{
buffer[i] = s.buffer[i];
}
}
}
By the way thanks for the great feedback and help. I feel like I am learning a lot about memory management.
Last edited on Jun 29, 2015 at 4:02pm UTC
Jun 29, 2015 at 5:05pm UTC
What is line 3 of your latest code fragment intended to do?
How does your latest version of handle?
1 2 3 4
String test("Hello" );
string blank;
test = blank;
What do you want to happen?
Andy
Last edited on Jun 29, 2015 at 5:12pm UTC