Attempting to troubleshoot copy constructor crash issue - c++

I've been attempting to troubleshoot this code with no avail. It crashed just as I call the copy constructor. In other attempts at calling the copy constructor the output of the new object has been random characters.
I have a feeling that my lack of understanding of memory management carries over to overloading the = operator too.
Here is my copy constructor....
MyString::MyString(const MyString& obj)
{
delete [] str;
int temp=obj.len;
len = temp;
str = new char[len];
for (int i = 0; i < len; i++)
{
char temp=obj.str[i];
str[i] = temp;
}
}
Here is my overloaded = ....
MyString& MyString::operator=(const MyString& obj)
{
delete [] str;
int temp = obj.len;
len = temp;
str = new char[len];
for ( int i = 0; i<=len; i++)
{
char temp = obj.str[i];
str[i] = temp;
}
str[len] = '\0';
return *this;
}
in the main method I call the copy constructor like so...
MyString stt3(str2); //str2 already exists.
Can anyone suggest where I'm going wrong?

The line
delete [] str;
in the copy constructor is not right. str is not initialized before that line. Removing that line should help, if not remove all the problems.
Also, you probably need to allocate one more object than len and null terminate str.
str = new char[len+1]; // Need +1
...
str[len] '\0';
You also need to change the call to new char[] in the assignment operator function too. You need:
str = new char[len+1];

Related

push_back struct into vector

//prototype
void Split(char c, vector <MyString> &outputVector) const
//partial code inside split function
// create new MyString object to push into output vector
MyString substr;
substr.mString = newString;
substr.mLength = size;
// push new item
outputVector.push_back(substr);
After I step over the outputVector.push_back() line, the mString data member is not retained.
//I have two constructors
MyString()
{
mString = NULL;
mLength = 0;
}
/*************************************************
* MyList copy constructor
* creates a deep copy of a MyString item
************************************************/
MyString(const MyString &copy)
{
mString = new char[copy.mLength];
int i;
for(; i < copy.mLength; i++)
{ mString[i] = copy.mString[i]; }
mString[i] = '\0';
mLength = copy.mLength;
}
You are using an uninitialized variable which is undefined behavior
int i;
for(; i < copy.mLength; i++)
Here we have no idea what i is so anything can be going on but most likely i is larger than copy.mLength so we never enter the for loop. In order to get correct behavior set i to 0 like
int i = 0;
You have another issue with
mString[i] = '\0';
By the time we reach that line i == copy.mLength but the array only has the size of copy.mLength so we are one past the end since arrays are 0 index based. Most likely you need to change your allocation to
mString = new char[copy.mLength + 1];
to give you space for the null terminator.
http://www.cplusplus.com/reference/vector/vector/push_back/
push_back copies value to vector. Does MyString class have properly defined copy constructor, that copies mString member? I would guess this might be your problem.
I think there are 2 mistakes ,you have done
1.for(i; i < copy.mLength; i++)
{ mString[i] = copy.mString[i]; }
you have to mention ,where the loop will start .
2.mString = new char[copy.mLength + 1];
mString[i] = '\0';
i think ,you got the answer :)
Correct version of copy constructor
MyString(const MyString &copy)
{
mString = new char[copy.mLength + 1];
int i = 0;
for(; i < copy.mLength; i++)
{ mString[i] = copy.mString[i]; }
mString[i] = '\0';
mLength = copy.mLength;
}

Getting double free error when not using copy constructor

class String
{
private:
    char *s;
    int size;
public:
   String(const char *str = NULL); // constructor
    ~String() { delete [] s;  }// destructor
    //String(const String&); // copy constructor --> i get double free error while running without this
    void print() { cout << s << endl; } // Function to print string
    void change(const char *);  // Function to change
};
String::String(const char *str)
{
    size = strlen(str);
    s = new char[size+1];
    strcpy(s, str);
}
void String::change(const char *str)
{
    delete [] s;
    size = strlen(str);
    s = new char[size+1];
    strcpy(s, str);
}
/*String::String(const String& old_str)
{
    size = old_str.size;
    s = new char[size+1];
    strcpy(s, old_str.s);
}*/
int main()
{
    String str1("Hello");
    String str2 = str1;
    str1.print(); // printed
    str2.print();
    str2.change("Helloworld");
    str1.print(); // not printed
    str2.print();// printed
    return 0;
}
http://ideone.com/xJtoTf
I am getting a double free error and the print for str1 is not being printed the second time (see comments in the code above)...
Is it because when i am not using copy constructor here, instead of default copy constructor being invoked assignment operator is used and both str2 and str1 are pointing to same location?
String str2 = str1; calls the copy constructor, not the assignment operator.
As you don't provide the copy constructor, the compiler will supply one automatically. All that will do is copy the member data.
So both str2 and str1 will share the same character buffer. Boom!

copy constructor failure... overloading, dynamic allocation

I'm working with dynamic strings, and there is an issue with copy constructor and overloading.
I'm using an operator+ to overload. the overloaded function is used to interpolate two char * strings.
here's just an excerpt of the code:
MyString::~MyString()
{
delete[] text; //char *text, as my private data
}
MyString::MyString(const MyString & obj)//copy constructor here
{
text = new char[obj.len];
for (int i = 0; i < obj.len; i++)
{
text[i] = obj.text[i];
}
len = obj.len;
}
MyString MyString::operator+(MyString & s)
{
MyString temp;
temp.len = len + s.len + 1;
int i;
for (i = 0; i < len; i++)
{
temp.text[i] = this->text[i];
}
for (int i = 0; i < s.len; i++)
{
temp.text[i + len] = s.text[i];
}
temp.text[len + s.len] = 0;
return temp;//PROBLEM HERE
}
and here's my problem:
the operator+ function calls both copy constructor and destructor before returning temp
and though there IS a copy constructor what is returned, is a deleted [] array.
what's the catch? Thanks
Lets say you have the following code
MyString s1; // Initialized to something
MyString s2; // Initialized to something else
MyString s3 = s1 + s2;
Then the expression s1 + s2 creates a temporary copy (the one returned by your operator+ function). This temporary copy is then passed to the copy-constructor to create s3 followed by the destruction of the temporary object.
That's the theory anyway, in reality the compiler will elide the copying.
Make these changes and try :
1. temp.text[len + s.len] = '\0'; //Null terminated
MyString**&** MyString::operator+(MyString & s)
{
.
.
.
}
//Return by reference, you will get the correct result.

Returning a local object results in garbage, while returning the same object temporary works fine

I'm currently implementing my own string class (just for training), but I'm experiencing some problems in my substr() method:
MyString MyString::substr(size_t position, size_t length)
{
if (checkBounds() || length == 0)
{
return MyString();
}
char* tmp = new char[length + 1];
memcpy(tmp, this->s + position, length);
tmp[length] = STRING_ESCAPE;
MyString result(tmp);
delete[] tmp;
tmp = nullptr;
return result;
}
When I call this method and print the return value (I'm printing the char array actuallay, not the object itself), I receive complete garbage, which is carried out as a bunch of squares.
But when I return a temporary object return MyString(tmp), everything works fine. Initially i suspected this issue is associated to the delete[] operation, but commenting it out shows no effect.
The MyString constructor which is called is the following:
MyString::MyString(const char* s)
{
size_t length = this->strlen(s);
this->sLength = length;
this->s = new char[length + 1];
for (size_t i = 0; i <= length; ++i)
{
this->s[i] = *s;
++s;
}
}
So where is my mistake? Thank you!
In the two places you create MyString, they are being created within the context of your substr function. The return statement has to make a copy of them. Your copy constructor is probably not doing what you would need it to do.
A simpler design is for your substr function to return a pointer to a MyString that you create with operator new.
You were indeed missing the copy constructor. Something like this would do the work:
MyString::MyString(const MyString& other) {
size_t length = strlen(other.s);
s = new char[length+1];
strcpy(s,other.s);
this->sLength = length;
}

<< operator overloading returning null on using destructor

#include<iostream>
using namespace std;
class MyString{
private:
char *str=new char[10];
public:
MyString(){*str='\0';} //default constructor
MyString(char *s){ //parameterized constructor
str=s;
}
private:
int length(char* s){
int i=0;
while(s[i]!='\0')
i++;
return i;
}
char* delchar(char* s,int count,int start){
int i,j=0;
char *temp= new char[10];
for(i=start;i<start+count;i++){
s[i]=' ';
}
for(i=0;i<length(s);i++){
if(s[i]!=' ')
temp[j++]=s[i];
}
s=temp;
return s;
}
public:
MyString operator-(MyString s){
int i=0,j=0,count=0,start=-1;/* i to iterate the first string,j to iterate the second string*/
MyString temp; /* count to count the matched characters ,start to know the starting index*/
temp.str=str;
while(temp.str[i]!='\0'){
j=0;
start++;
while(s.str[j]!='\0'){
if(temp.str[i]==s.str[j]){
count++;
i++;
j++;
if(count==length(s.str)){//checks if the count
temp.str=delchar(temp.str,count,start);
i=i-count;
start=i-1;
count=0;
}
}
else{
i++;
count=0;
break;
}
}
}
return temp;
}
~MyString(){
delete str;
}
friend ostream &operator<<(ostream &stream,MyString& s){
stream<<s.str<<endl;
return stream;
}
};
int main(){
char *p= new char[20];
char *q= new char[10];
cin>>p;
cin>>q;
MyString s1(p);
MyString s2(q);
MyString s3;
s3=s1-s2;
cout<<s3;
delete p;
delete q;
return 0;
}
The above code overloads the - operator .It tries to subtract the substring from the main string for example input1:joshmathews input2:josh output:mathews. I am trying to store the output in a new MyString object s3. When I use a destructor as shown above,outputting s3
returns null. But when I don't use a destructor I get the expected output.Can anyone help?
The primary issue is that Operater- returns a local object which is copied by a default copy constructor -- that default copy constructor points s3 to the exact same memory/buffer of the temp MyString, and when that temp is destructed, it wipes out the memory s3 is using.
That is referred to as a dangling pointer. You can read more here: http://en.wikipedia.org/wiki/Dangling_pointer#Cause_of_wild_pointers
The code below is the changes I made to get your program executing and returning a valid result, while completing without error. To be clear though, there are issues with this altered version, runtime error or no runtime error, but this will help illuminate some important points.
When you define a type that allocates memory, you've really started to do somethings that don't come free. My altered version below completely got rid of the destructor, so actually it leaks memory up until the program ends. The destructor was invalid though, so removing it allowed the program the finish. But this would be one of those things that in general you shouldn't just accept.
I added a copy constructor and a copy assignment operator:
MyString(const MyString& s) {
strcpy_s(str, 10, s.str);
}
MyString& operator=(const MyString& s) {
strcpy_s(str, 10, s.str);
return *this;
}
Notice the strcpy_s in both of these. What is doing is copy the character string from the argument instead of just trying to point at the exact same string at the exact same address as the argument. If the argument gets destructed in your version, it wipes out some memory, so we can just accept default copy constructor and such since by default they are shallow copies that point to the same guts. That's one of the burdens of allocating memory -- you need to take care of that in both your destructor's ~and~ some of your constructors. This is referred to as "The Rule of Three":
If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
Here's a wikipedia link about the rule of three: http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
You needed a destructor, so that's the clue you need the others. The reason is as I was saying -- by default you get a copy constructor for free, but it just makes everything point to the same guts if there are points are resources, but then you can't delete one without affecting everybody else.
Also, in delchar I added this line towards the bottom:
temp[j] = '\0';
Characters strings must always end at a null, and you copied only actual letter characters into temp, so without a null character, a strcpy doesn't know where to end.
If you remember I yanked out your destructor, then those are the changes I made.
The destructor also has an issue, in that if you use new to create an array, like
char* c = new char[10];
then you need to delete it in a way that indicates in was new'd as an array, like so:
delete [] c;
The next thing you should look into is how your MyString construction happens. If you step through, you'll see that the str member get new'd -- that means it holds a valid address into a buffer you can use -- but then if the MyString(char *s) constructor is used, it literally just takes this new address of s, and makes str hold that address instead -- which means the old address pointing to the valid buffer is lost, and that buffer of new'd memory cannot be freed. So that's a leak. You could use the strcpy_s strategy from the constructors I added to copy the contexts of what is pointed to by the s in MyString(char *s) into the new'd buffer. That would make a huge positive difference in the code.
And don't bother about all the elitists out there -- many of them were born doing headstands, so they can't see to relate to newbies giving things an honest effort.
Here's the full altered code:
#include<iostream>
using namespace std;
class MyString{
private:
char *str = new char[10];
public:
MyString(){ *str = '\0'; } //default constructor
MyString(char *s){ //parameterized constructor
str = s;
}
MyString(const MyString& s) {
strcpy_s(str, 10, s.str);
}
MyString& operator=(const MyString& s) {
strcpy_s(str, 10, s.str);
return *this;
}
private:
int length(char* s){
int i = 0;
while (s[i] != '\0')
i++;
return i;
}
char* delchar(char* s, int count, int start){
int i, j = 0;
char *temp = new char[10];
for (i = start; i<start + count; i++){
s[i] = ' ';
}
for (i = 0; i<length(s); i++){
if (s[i] != ' ')
temp[j++] = s[i];
}
temp[j] = '\0';
s = temp;
return s;
}
public:
MyString operator-(MyString s){
int i = 0, j = 0, count = 0, start = -1;/* i to iterate the first string,j to iterate the second string*/
MyString temp; /* count to count the matched characters ,start to know the starting index*/
temp.str = str;
while (temp.str[i] != '\0'){
j = 0;
start++;
while (s.str[j] != '\0'){
if (temp.str[i] == s.str[j]){
count++;
i++;
j++;
if (count == length(s.str)){//checks if the count
temp.str = delchar(temp.str, count, start);
i = i - count;
start = i - 1;
count = 0;
}
}
else{
i++;
count = 0;
break;
}
}
}
return temp;
}
~MyString(){
//delete str;
}
friend ostream &operator<<(ostream &stream, MyString& s){
stream << s.str << endl;
return stream;
}
};
int main(){
char *p = new char[20];
char *q = new char[10];
cin >> p;
cin >> q;
MyString s1(p);
MyString s2(q);
MyString s3;
s3 = s1 - s2;
cout << s3;
delete p;
delete q;
return 0;
}