C++ Delete[] causing program crash [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
My program works fine while I don't have a call to delete[] buf in the destructor. However, when I include it the program crashes at the start of the output.
Here are my files.
//string.cpp
#include "String.h"
#include
#include
extern ofstream csis;
String::String() {
buf = "\0";
length = 0;
}
String::String(const char* tar) {
int temp = strlen(tar);
length = temp;
buf = new char[length + 1];
buf[length] = '\0';
for (int i = 0; i < length; i++){
buf[i] = tar[i];
}
}
String::String(char a) {
length = 1;
buf = new char[length+1];
buf[length] = '\0';
buf[0] = a;
}
String::String(int x) {
int alloc = x;
if (x < 0) {
alloc = 0;
}
buf = new char[alloc+1];
length = x;
buf[0] = '\0';
}
String::String(const String& a) {
length = a.length;
buf = new char[length+1];
for (int i = 0; i < length; i++) {
buf[i] = a.buf[i];
}
}
String::String(char a, int x) {
buf = new char[x+1];
for (int i = 0; i < x; i++) {
buf[i] = a;
}
buf[x] = '\0';
length = strlen(buf);
}
String::~String() {
delete buf;
}
String& String::operator=(const String& tar) {
buf = new char[tar.length+1];
strcpy(buf, tar.buf);
length = tar.length;
buf[length] = '\0';
return *this;
}
String& String::operator=(const char* chr) {
buf = (char*)chr;
length = int(strlen(chr));
return *this;
}
String operator+(const String& a, const String& b) {
String sum;
int size = a.length + b.length;
sum.buf = new char[size+1];
sum.length = size;
for (int i = 0; i < a.length; i++) {
sum.buf[i] = a.buf[i];
}
int j = 0;
for (int i = a.length; i < size; i++) {
sum.buf[i] = b.buf[j];
j++;
}
sum.buf[size] = '\0';
return sum;
}
String operator+(const String& tar, const char* c) {
String sum;
int size = int(strlen(c)) + tar.length;
sum.buf = new char[size+1];
sum.length = size;
for (int i = 0; i < tar.length; i++) {
sum.buf[i] = tar.buf[i];
}
int j = 0;
for (int i = tar.length; i < size; i++) {
sum.buf[i] = c[j];
j++;
}
sum.buf[size] = '\0';
return sum;
}
String operator+(const char* c, const String& tar) {
String sum;
int size = int(strlen(c)) + tar.length;
sum.buf = new char[size+1];
sum.length = size;
for (int i = 0; i < int(strlen(c)); i++) {
sum.buf[i] = c[i];
}
int j = 0;
for (int i = strlen(c); i < size; i++) {
sum.buf[i] = tar.buf[j];
j++;
}
sum.buf[size] = '\0';
return sum;
}
String operator+(const String& tar, char c) {
String sum;
int size = 1 + tar.length;
sum.buf = new char[size];
sum.length = size;
for (int i = 0; i < tar.length; i++) {
sum.buf[i] = tar.buf[i];
}
int j = 0;
for (int i = tar.length; i < size; i++) {
sum.buf[i] = c;
j++;
}
sum.buf[size] = '\0';
return sum;
}
String operator+(char c, const String& tar) {
String sum;
int size = 1 + tar.length;
sum.buf = new char[size+1];
sum.length = size;
for (int i = 0; i < 1; i++) {
sum.buf[i] = c;
}
int j = 0;
for (int i = 1; i < size; i++) {
sum.buf[i] = tar.buf[j];
j++;
}
sum.buf[size] = '\0';
return sum;
}
String& String::operator+=(const String& tar) {
String temp = *this;
temp = temp + tar;
*this = temp;
return *this;
}
String& String::operator+=(const char c) {
String temp = *this;
temp = temp + c;
*this = temp;
return *this;
}
String String::operator+() const {
String sum;
sum.length = length;
sum.buf = new char[sum.length+1];
strcpy(sum.buf, buf);
for (int i = 0; i < length; i++) {
sum.buf[i] = toupper(buf[i]);
}
sum.buf[length] = '\0';
return sum;
}
int operator==(const String & tar, const String& tar2) {
int check = 0;
if (strcmp(tar.buf, tar2.buf) == 0) {
check += 1;
}
else if (strcmp(tar.buf, tar2.buf) != 0) {
check = 0;
}
return check;
}
int operator!=(const String& tar, const String& tar2) {
int check = 0;
if (!(strcmp(tar.buf, tar2.buf) == 0)) {
check += 1;
}
else if (!(strcmp(tar.buf, tar2.buf) != 0)) {
check = 0;
}
return check;
}
int operator<(const String& a, const String& b) {
int check = 0;
if (a.length < b.length) {
check += 1;
}
return check;
}
int operator<=(const String& a, const String& b) {
int check = 0;
if (a.length <= b.length) {
check += 1;
}
return check;
}
int operator>(const String& a, const String& b) {
int check = 0;
if (a.length > b.length) {
check += 1;
}
return check;
}
int operator>=(const String& a, const String& b) {
int check = 0;
if (a.length >= b.length) {
check += 1;
}
return check;
}
char& String::operator[](int x) {
int out;
if (x >= 0 && x < length) {
out = x;
}
else if (!(x >= 0 && x < length)) {
int output = NULL;
cout << "ERROR: Invalid Index with [] operator." << endl;
csis << "ERROR: Invalid Index with [] operator." << endl;
out = NULL;
}
return buf[out];
}
char* operator+(const String& a, int x) {
return &a.buf[x];
}
char* operator+(int x, const String& a) {
return &a.buf[x];
}
String String::operator++(int val) {
String temp;
temp = *this;
for (int i = 0; i < temp.length; i++) {
temp.buf[i] = temp.buf[i] + 1;
}
return temp;
}
String String::operator--(int val) {
String temp;
temp = *this;
for (int i = 0; i < temp.length; i++) {
temp.buf[i] = temp.buf[i] - 1;
}
return temp;
}
String String::operator++() {
String temp = *this;
for (int i = 0; i < temp.length; i++) {
temp.buf[i] = (temp.buf[i] + 1);
}
return temp;
}
String String::operator--() {
String temp = *this;
for (int i = 0; i < temp.length; i++) {
temp.buf[i] = (temp.buf[i] - 1);
}
return temp;
}
int String::getLength() {
return length;
}
String String::substr(int a, int b) {
String temp = *this;
char *fill = new char[b+1];
int i = a;
int x = 0;
while (x <= b) {
fill[i] = temp.buf[i];
i++;
x++;
}
temp.buf = fill;
temp.buf[length] = '\0';
return temp;
}
void String::print() {
cout << """";
csis << """";
for (int i = 0; i < length; i++) {
cout << buf[i];
csis << buf[i];
}
cout << """";
csis << """";
cout << " Length: " << length << endl;
csis << " Length: " << length << endl;
}
ostream& operator<<(ostream& o, const String& tar) {
for (int i = 0; i < tar.length; i++) {
o << tar.buf[i];
}
return o;
}
Here is string.h
//string.h
#ifndef _STRING_H
#define _STRING_H
#include <iomanip>
#include <stdlib.h>
#include <iostream>
using namespace std;
class String {
protected:
int length;
char* buf;
public:
String();
String(const char*);
String(char a);
String(int x);
String(const String&);
String(char a, int x);
~String();
// Operator Overload
String& operator=(const String& tar);
String& operator= (const char*);
friend String operator+(const String& a, const String& b);
friend String operator+(const String&, const char*);
friend String operator+(const char* c, const String& tar);
friend String operator+(const String&, char c);
friend String operator+(char c, const String& tar);
String& operator+=(const String& tar);
String& operator+=(const char c);
String operator+() const;
friend int operator==(const String&, const String&);
friend int operator!=(const String&, const String&);
friend int operator<(const String&, const String&);
friend int operator<=(const String&, const String&);
friend int operator>(const String&, const String&);
friend int operator>=(const String&, const String&);
char& operator[](int);
friend char* operator+(const String&, int);
friend char* operator+(int, const String&);
String operator++();
String operator--();
String operator++(int);
String operator--(int);
int getLength();
String substr(int a, int b);
void print();
friend ostream& operator<<(ostream&, const String&);
};
#endif
Here is StringDriver.cpp
// StringDriver.cpp
// MATTHEW BUTNER
// ID: 011029756
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "StringDriver.h"
using namespace std;
ofstream csis;
int main() {
csis.open("csis.txt");
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
test11();
test12();
test13();
test14();
test15();
test16();
test17();
test18();
test19();
test20();
csis.close();
}
void test1() {
cout << "1. Testing S1: String default ctor." << endl << endl;
csis << "1. Testing S1: String default ctor." << endl << endl;
String s1;
s1.print();
wait();
}
void test2() {
cout << "2. Testing S2: String one arg (char *) ctor." << endl << endl;
csis << "2. Testing S2: String one arg (char *) ctor." << endl << endl;
String s2("ABC");
s2.print();
wait();
}
void test3() {
cout << "3. Testing S3: String one arg (char) ctor." << endl << endl;
csis << "3. Testing S3: String one arg (char) ctor." << endl << endl;
String s3('Z');
s3.print();
wait();
}
void test4() {
cout << "4. Testing S4: String one arg (int) ctor." << endl << endl;
csis << "4. Testing S4: String one arg (int) ctor." << endl << endl;
String s4(10);
s4.print();
wait();
}
void test5() {
cout << "5. Testing S5, T5: String copy ctor." << endl << endl;
csis << "5. Testing S5, T5: String copy ctor." << endl << endl;
String s5("Purple Rain");
s5.print();
String t5(s5);
t5.print();
wait();
}
void test6() {
cout << "6. Testing S6: String two arg (char, int) ctor." << endl << endl;
csis << "6. Testing S6: String two arg (char, int) ctor." << endl << endl;
String s6('*', 10);
s6.print();
wait();
}
void test7() {
cout << "7. Testing S7, T7, U7: String assignment." << endl << endl;
csis << "7. Testing S7, T7, U7: String assignment." << endl << endl;
String s7("Sally Ride"), t7, u7;
t7 = u7 = s7;
s7.print();
t7.print();
u7.print();
wait();
}
void test8() {
cout << "8. Testing S8: String assignment." << endl << endl;
csis << "8. Testing S8: String assignment." << endl << endl;
String s8("ABC");
s8 = s8;
s8.print();
wait();
}
void test9() {
cout << "9. Testing S9: Implicit type conversion." << endl << endl;
csis << "9. Testing S9: Implicit type conversion." << endl << endl;
String s9;
s9 = "ABC";
s9.print();
wait();
}
void test10() {
cout << "10. Testing S10, T10, U10: String concatenation." << endl << endl;
csis << "10. Testing S10, T10, U10: String concatenation." << endl << endl;
String s10("DEF");
String t10('H');
String u10("ABC" + s10 + "G" + t10 + 'I');
u10.print();
String v10('X' + u10);
v10.print();
wait();
}
void test11() {
cout << "11. Testing S11, T11: String concatenation." << endl << endl;
csis << "11. Testing S11, T11: String concatenation." << endl << endl;
String s11('A');
String t11("BC");
s11 += s11 += t11 += 'D';
s11.print();
t11.print();
wait();
}
void test12() {
cout << "12. Testing S12, T12: String unary operator." << endl << endl;
csis << "12. Testing S12, T12: String unary operator." << endl << endl;
String s12("Unary +");
String t12(+s12);
s12.print();
t12.print();
s12 = +s12;
s12.print();
wait();
}
void test13() {
cout << "13. Testing S13, T13: String comparison operators." << endl << endl;
csis << "13. Testing S13, T13: String comparison operators." << endl << endl;
String s13("ABC"), t13("ABCD");
s13.print();
t13.print();
cout << endl;
cout << "== " << (s13 == t13 ? "True" : "False") << endl;
cout << "!= " << (s13 != t13 ? "True" : "False") << endl;
cout << "< " << (s13 < t13 ? "True" : "False") << endl;
cout << "<= " << (s13 <= t13 ? "True" : "False") << endl;
cout << "> " << (s13 > t13 ? "True" : "False") << endl;
cout << ">= " << (s13 >= t13 ? "True" : "False") << endl;
csis << endl;
csis << "== " << (s13 == t13 ? "True" : "False") << endl;
csis << "!= " << (s13 != t13 ? "True" : "False") << endl;
csis << "< " << (s13 < t13 ? "True" : "False") << endl;
csis << "<= " << (s13 <= t13 ? "True" : "False") << endl;
csis << "> " << (s13 > t13 ? "True" : "False") << endl;
csis << ">= " << (s13 >= t13 ? "True" : "False") << endl;
wait();
}
void test14() {
cout << "14. Testing S14: Overloaded subscript operator." << endl << endl;
csis << "14. Testing S14: Overloaded subscript operator." << endl << endl;
String s14("C++ is fun.");
for (int i = -1; i <= s14.getLength(); i++) {
char& ch = s14[i];
if (ch != '\0')
++ch;
}
s14.print();
wait();
}
void test15() {
cout << "15. Testing S15: Pointer notation." << endl << endl;
csis << "15. Testing S15: Pointer notation." << endl << endl;
String s15("ABCDE");
for(int i = 0; i < s15.getLength(); i++)
++(*(s15+i));
for (int j = 0; j < s15.getLength(); j++) {
cout << *(j + s15);
csis << *(j + s15);
}
cout << endl;
csis << endl;
wait();
}
void test16() {
cout << "16. Testing S16, T16, U16, V16, W16, X16, Y16, Z16: Increment and decrement operators." << endl << endl;
csis << "16. Testing S16, T16, U16, V16, W16, X16, Y16, Z16: Increment and decrement operators." << endl << endl;
String s16("ABC");
String t16(++s16);
s16.print();
t16.print();
String u16("ABC");
String v16(u16++);
u16.print();
v16.print();
String w16("ABC");
String x16(--w16);
w16.print();
x16.print();
String y16("ABC");
String z16(y16--);
y16.print();
z16.print();
wait();
}
void test17() {
cout << "17. Testing S17, T17: Substr function." << endl << endl;
csis << "17. Testing S17, T17: Substr function." << endl << endl;
String s17("All You Need Is Love"), t17;
t17 = s17.substr(4, 8);
s17.print();
t17.print();
wait();
}
void test18() {
cout << "18. Testing S18, T18: Output function." << endl << endl;
csis << "18. Testing S18, T18: Output function." << endl << endl;
String s18("Red-");
String t18("Green-");
String u18("Blue");
cout << s18 << t18 << u18;
csis << s18 << t18 << u18;
cout << endl;
csis << endl;
wait();
}
void test19() {
cout << "19. Testing S19, T19, U19: ReverseString class." << endl << endl;
csis << "19. Testing S19, T19, U19: ReverseString class." << endl << endl;
ReverseString s19("Computer");
ReverseString t19;
t19 = ~s19;
s19.print();
t19.print();
ReverseString u19(~~s19);
u19.print();
wait();
}
void test20() {
cout << "20. Testing S20, T20, U20: CaseString class." << endl << endl;
csis << "20. Testing S20, T20, U20: CaseString class." << endl << endl;
CaseString s20("BaLLooN");
CaseString t20;
t20 = s20;
s20.print();
t20.print();
CaseString u20(s20);
u20.print();
wait();
}
void wait() {
char buf;
cout << endl << "Press any key to continue." << endl;
csis << endl << endl;
cin.get(buf);
}
The problem is with the destructor in string.cpp, when I have an empty destructor, everything goes fine and well, but when I include the delete buf, it'll crash the program. Also, here are the other .h and .cpp files:
//ReverseString.h
#ifndef _REVERSESTRING_H
#define _REVERSESTRING_H
#include "String.h"
#include <iostream>
class ReverseString : public String {
public:
ReverseString();
ReverseString(const ReverseString& tar);
ReverseString(const char* c);
ReverseString& operator=(const ReverseString&);
ReverseString operator~();
};
#endif
next file,
//ReverseString.cpp
#include "ReverseString.h"
extern ostream csis;
ReverseString::ReverseString() : String() {
}
ReverseString::ReverseString(const ReverseString& tar) : String(tar) {
}
ReverseString::ReverseString(const char* c) : String(c) {
}
ReverseString& ReverseString::operator=(const ReverseString& tar) {
length = tar.length;
buf = tar.buf;
buf[length] = '\0';
return *this;
}
ReverseString ReverseString::operator~() {
ReverseString reverse;
reverse.length = length;
reverse.buf = new char[length];
int j = length - 1;
for (int i = 0; i < length; i++) {
reverse.buf[i] = buf[j];
j--;
}
return reverse;
}
CaseString.h
#ifndef _CASESTRING_H
#define _CASESTRING_H
#include "String.h"
#include <iostream>
class CaseString : public String {
protected:
char* upper;
char* lower;
public:
CaseString();
CaseString(const CaseString& tar);
CaseString(const char* c);
CaseString& operator=(const CaseString& c);
void print();
~CaseString();
};
#endif
CaseString.cpp
#include "CaseString.h"
#include <fstream>
extern ofstream csis;
CaseString::CaseString() : String() {
}
CaseString::CaseString(const CaseString& tar) : String(tar) {
upper = tar.upper;
lower = tar.lower;
buf = tar.buf;
length = tar.length;
}
CaseString::CaseString(const char* c) : String(c) {
lower = new char[int(strlen(c))];
upper = new char[int(strlen(c))];
int losize = strlen(c);
char* getLow = new char[losize];
for (int i = 0; i < losize; i++) {
getLow[i] = tolower(c[i]);
}
char* getHi = new char[losize];
for (int i = 0; i < losize; i++) {
getHi[i] = toupper(c[i]);
}
lower = getLow;
upper = getHi;
lower[losize] = '\0';
upper[losize] = '\0';
}
CaseString& CaseString::operator=(const CaseString& tar) {
if (&tar != this) {
String::operator=(tar);
buf = tar.buf;
length = tar.length;
lower = tar.lower;
upper = tar.upper;
}
return *this;
}
void CaseString::print() {
cout << "\"" << buf << "\"" << " " << "Length = " << length << " |" << "Lower = " << lower << " |" << "Upper = " << upper << endl;
csis << "\"" << buf << "\"" << " |" << "Length = " << length << " |" << "Lower = " << lower << " |" << "Upper = " << upper << endl;
}
CaseString::~CaseString() {
}

There are several issues that I see.
The main problem is that you sometimes assign a pointer to a character string to buf (your default constructor is one such place, and there is at least one other). This is a pointer you do not want to delete. You need to either always allocate memory for buf, or have some way to tell if you own the pointer and it should be deleted.
The other issue is that since you use new [], you need to use delete [] buf in your destructor.
In your copy constructor, you do not copy the nul byte at the end of the coped buffer.

Related

Why we have to use const in copy constructor and assignment operator in visual studio 2019 and onwards versions

As you can see that operator+ is returning an object of class type MyString.
The assignment operator is not accepting this object in Visual Studio 2019 and giving an error of E0349 that no operands matches. But, in Visual Studio 2012, it is running fine.
Code:
#include <iostream>
using namespace std;
class MyString {
private:
char* str;
int length;
public:
MyString();
MyString(const MyString&);
bool operator!();
friend ostream& operator<<(ostream&, MyString&);
friend istream& operator>>(istream&, MyString&);
MyString& operator=(const MyString&);
MyString operator+(MyString&);
MyString& operator-(MyString);
MyString& operator ++ ();
MyString& operator -- ();
bool operator<(MyString&);
char& operator[](int);
char* operator()(int, int);
void my_strcpy(char*&, char*);
int my_strlen(char*);
};
MyString::MyString() {
str = new char[1];
str[0] = '\0';
length = 0;
}
MyString::MyString(const MyString& obj) {
int size = my_strlen(obj.str) + 1;
str = new char[size];
cout << "copy constructor called\n";
my_strcpy(str, obj.str);
}
bool MyString::operator!() {
if (str[0] == '\0')
return true;
return false;
}
ostream& operator<<(ostream& output, MyString& obj) {
output << obj.str;
return output;
}
istream& operator>>(istream& input, MyString& obj) {
delete obj.str;
obj.str = new char[50];
input.getline(obj.str, 50);
return input;
}
MyString& MyString::operator=(const MyString& obj) {
if (this != &obj) {
my_strcpy(str, obj.str);
}
return *this;
}
char& MyString::operator[](int index) {
if (index >= 0 && index < my_strlen(str))
return str[index];
else {
clog << "Index is out of range\n", exit(1);
}
}
void MyString::my_strcpy(char*& destination, char* source) {
int len_des = my_strlen(destination);
int len_source = my_strlen(source);
delete[]destination;
destination = new char[len_source + 1];
int index = 0;
while (source[index] != '\0')
destination[index] = source[index++];
destination[index] = '\0';
}
MyString MyString::operator+(MyString& obj) {
MyString newObj;
int size = my_strlen(str) + my_strlen(obj.str) + 1;
newObj.str = new char[size];
char* temp = newObj.str;
int index_str = 0;
while (str[index_str] != '\0')
*newObj.str++ = str[index_str++];
index_str = 0;
while (obj.str[index_str] != '\0')
*newObj.str++ = obj.str[index_str++];
*newObj.str = '\0';
newObj.str = temp;
cout << newObj.str << endl;
return newObj;
}
MyString& MyString::operator ++ () {
int size = my_strlen(str) + 2;
char* new_str = new char[size];
char* temp = new_str;
int index = 0;
while (str[index] != '\0')
*new_str++ = str[index++];
*new_str++ = 'a';
*new_str = '\0';
delete[]str;
str = temp;
return *this;
}
MyString& MyString::operator -- () {
int size = my_strlen(str);
char* new_str = new char[size];
char* temp = new_str;
int index = 0;
while (index < size - 1)
*new_str++ = str[index++];
*new_str = '\0';
delete[]str;
str = temp;
return *this;
}
MyString& MyString::operator-(MyString obj) {
bool find = true;
int obj_str_len = my_strlen(obj.str);
int str_len = my_strlen(str);
int start_ind = 0, end_ind = 0;
if (str_len > obj_str_len) {
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == obj.str[0]) {
start_ind = i;
find = true;
for (int j = i + 1, k = 1; obj.str[k] != '\0' && find; j++, k++) {
if (str[j] != obj.str[k]) {
find = false;
}
end_ind = j + 1;
}
if (find)
break;
}
}
if (find) {
while (str[end_ind] != '\0') {
str[start_ind++] = str[end_ind++];
}
str[str_len - (end_ind - start_ind)] = '\0';
}
}
return *this;
}
bool MyString::operator<(MyString& obj) {
if (my_strlen(str) < my_strlen(obj.str))
return true;
else if (my_strlen(str) > my_strlen(obj.str))
return false;
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] < obj.str[i])
return true;
else if (str[i] > obj.str[i]) {
return false;
}
}
return false;
}
char* MyString::operator()(int starting_index, int ending_index) {
int new_str_size = ending_index - starting_index + 2;
char* new_str = new char[new_str_size];
char* temp = new_str;
int index = 0;
int str_len = my_strlen(str);
while (starting_index < str_len && index < 10)
*new_str++ = str[starting_index++], index++;
*new_str = '\0';
return temp;
}
int MyString::my_strlen(char* str) {
int size = 0;
while (str[size] != '\0')
size++;
return size;
}
int main() {
MyString str1, str2, str3, str4, str6;
if (!str1)
{
cout << "String 1 is Empty.\n";
cout << "Str 1 = " << str1 << endl << endl << endl;
}
cout << "Enter String 1:\t";
cin >> str1;
cout << "Enter String 2:\t";
cin >> str2;
cout << "\n\n\nUser Entered:\n";
cout << "String 1 = " << str1 << endl;
cout << "String 2 = " << str2 << endl << endl << endl;
cout << "Before str1 = str1; str1 = " << str1 << endl;
str1 = str1;
cout << "After str1 = str1, str1 = " << str1 << endl << endl << endl;
cout << "Before str4 = str3 = str1+str2\n";
cout << "str1 = " << str1 << endl;
cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;
str4 = str3 = str1 + str2;
cout << "\n\n\nAfter str4 = str3 = str1+str2\n";
cout << "str1 = " << str1 << endl;
cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;
cout << "\n\n\nEnter String 3:\t";
cin >> str3;
cout << "\n\n\nEnter String 4:\t";
cin >> str4;
cout << "\n\n\nstr3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;
if (str3 < str4)
cout << "String 3 is Less than String 4.\n";
else
cout << "String 3 is NOT Less than String 4.\n";
MyString str5 = str1 + str2;;
cout << "\n\n\nStr5:\t" << str5 << endl;
cout << "Str5[7]:\t" << str5[7] << endl;
str5[7] = '$';
cout << "\n\nStr5:\t" << str5 << endl;
cout << "\n\n\nstr5(5, 10):\t" << str5(5, 10) << endl;
cout << "\n\n ++Str3 :\t" << ++str3 << endl;
str5 = str4 - str3;
cout << "\n\n Str4 - Str3 :\t" << str5 << endl;
cout << "\n\n --Str3 :\t" << --str3 << endl;
cout << "\n\n --Str3 :\t" << --str3 << endl;
str5 = str4 - str3;
cout << "\n\n Str4 - str3 :\t" << str5 << endl;
return 0;
}
Problem:
The lines str3 = str1 + str2; and MyString str4 = str1 + str2; will give an error that no operands matches. This error starts from Visual Studio 2019 and onwards versions.
But, when I use const in both copy constructor and assignment operator (such as MyString(const MyString&); MyString& operator=(const MyString&);), both lines (str3 = str1 + str2; MyString str4 = str1 + str2;) looks fine to compiler.
But if I Write str3 = str1; and MyString str4 = str2; now there is no need to write const in the copy constructor and assignment operator.
Why is the compiler showing this behaviour.?
The assignment operator that you have defined (i.e., taking a non-const reference) requires that its argument be (or be convertible to) an lvalue reference because it is non-const.
However, the right-hand side of the assignment operator in the expression, str3 = str1 + str2 is the result of the addition, which is a temporary value and, as such, is a prvalue that cannot be (implicitly) converted to an lvalue.
Adding the const qualifier to the parameter allows that operator to accept rvalue references (because you are explicitly stating that the referred-to value will not be modified).
This is why, generally, copy constructors and copy assignment operators are defined with const &T parameters (though they don't have to be).
For a fuller discussion of the differences between lvalues and rvalues, see here: Exact difference between rvalue and lvalue.
On why/how this "binding of a temporary to an lvalue reference" was allowed in the earlier version(s) of Visual Studio, see: Non-const reference bound to temporary, Visual Studio bug?.

Operator Overloading solution

i have made a c++ code. An MList that holds items in it. I overloaded the << operator to print the values in MList in a particular format. Here is the code:
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
string s = "";
s += "Size " + to_string(m.size_) + "\n";//out << m.size() << endl;
s += "Cap " + to_string(m.capacity_) + "\n"; //out << m.capacity() << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
s += m.ary[i].element + ",";//out << m.ary[i].element << ",";
else
s += m.ary[i].element;
}
//cout << "String : " << s;
return out << s;
}
But it does not print correct value. It prints the size and capacity right but not the values. Instead of values, it prints some signs like heart:
You can see it prints size and capacity right but not the values. Here is the relevant code. I am executing case 2 only right now:
#include<iostream>
using std::cout; using std::endl;
using std::ostream; using std::cin; using std::boolalpha;
#include<string>
using std::string;
using namespace std;
template <class V>
struct SetElement
{
V element;
int cnt;
SetElement() = default;
SetElement(V v) : element(v){}
};
template <class V>
ostream &operator<<(ostream & o,const SetElement<V> &p)
{
return o << p.element;
}
template <class V>
class MSet
{
private:
SetElement<V> *ary;
size_t capacity_;
size_t size_;
public:
MSet(V val)
{
capacity_ = 2;
ary = new SetElement<V>[capacity_];
ary[0].element = val;
ary[0].cnt = 1;
size_ = 1;
}
SetElement<V>* find(V val)
{
SetElement<V> *found = nullptr;
bool yes = false;
for (int i = 0; i < size_ && !yes; i++)
{
if (ary[i].element == val)
{
found = &ary[i];
yes = true;
}
}
return found;
}
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
string s = "";
s += "Size " + to_string(m.size_) + "\n";//out << m.size() << endl;
s += "Cap " + to_string(m.capacity_) + "\n"; //out << m.capacity() << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
s += m.ary[i].element + ",";//out << m.ary[i].element << ",";
else
s += m.ary[i].element;
}
//cout << "String : " << s;
return out << s;
}
};
int main(){
int test;
long l1, l2, l3;
cin >> test;
cout << boolalpha;
switch (test){
// ...
case 2: {
cin >> l1 >> l2;
MSet<long> m_l(l1);
auto p = m_l.find(l1);
if (p != nullptr)
cout << *p << endl;
else
cout << "Val:" << l1 << " not found " << endl;
p = m_l.find(l2);
if (p != nullptr)
cout << *p << endl;
else
cout << "Val:" << l2 << " not found " << endl;
//cout << "MList \n";
cout << m_l;
break;
}
// ...
}
}
You're adding the values into a temporary string, which may involve implicit conversions depending of the template type (here your numerical values were converted into characters).
Just print the values, without the temporary string:
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
out << "Size " << m.size_ << endl;
out << "Cap " << m.capacity_ << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
out << m.ary[i].element << ",";
else
out << m.ary[i].element;
}
return out;
}

Destructor problems+ list display [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I have the following code:
The problem is when I create a list in main of type: Reteta.
After I display the list I receive am error of bad allocation. If I comment the destructor from the class Reteta the program works. Can you help me find the bug? Or maybe I didn't display the list well so the program have other problems to take care of.
Here is the code:
#include<iostream>
#include<fstream>
#include<list>
using namespace std;
class Medicament{
private:
char *denumire;
float pret;
public:
Medicament()
{
this->pret = 0;
this->denumire = new char[strlen("Fara denumire")];
strcpy(this->denumire, "Fara denumire");
}
Medicament(char* denumire, float pret)
{
this->denumire = new char[strlen(denumire) + 1];
strcpy(this->denumire, denumire);
this->pret = pret;
}
Medicament(const Medicament& x)
{
this->denumire = new char[strlen(x.denumire) + 1];
strcpy(this->denumire, x.denumire);
this->pret = x.pret;
}
~Medicament()
{
if (this->denumire)
{
delete[] this->denumire;
}
}
void setDenumire(char *x)
{
if (x)
{
if (this->denumire)
{
delete[] this->denumire;
}
this->denumire = new char[strlen(x) + 1];
strcpy(this->denumire, x);
}
}
char* getDenumire()
{
return this->denumire;
}
void setPret(float f)
{
if (f)
{
this->pret = f;
}
}
Medicament operator=(Medicament x)
{
this->denumire = new char[strlen(x.denumire) + 1];
strcpy(this->denumire, x.denumire);
this->pret = x.pret;
return *this;
}
friend ostream& operator<<(ostream& consola, Medicament &x)
{
consola << "Medicament: " << x.denumire << endl; //error here
consola << "Pret: " << x.pret << endl;
return consola;
}
float getPret()
{
return this->pret;
}
friend class Reteta;
};
class Reteta{
protected:
Medicament *medicamente;
int n;
public:
Reteta()
{
this->n = 0;
this->medicamente = NULL;
}
Reteta(Medicament *v, int n)
{
this->n = n;
this->medicamente = new Medicament[n];
for (int i = 0; i < n; i++)
{
this->medicamente[i] = v[i];
}
}
~Reteta()
{
if (this->medicamente)
{
delete[] this->medicamente; //The problem is here. If I comment this the program works.
}
}
int getN()
{
return this->n;
}
friend ostream& operator<<(ostream& consola, Reteta& x)
{
consola << "Numar de medicamente: " << x.n << endl;
consola << " -->Lista Medicamente<-- "<<endl;
for (int i = 0; i < x.n; i++)
{
consola << x.medicamente[i].getDenumire() <<endl; //error at this line when I compile
consola << x.medicamente[i].getPret()<< endl;
}
return consola;
}
void adaugaMedicament(Medicament x)
{
Reteta y;
y.medicamente= new Medicament[this->n+1];
for (int i = 0; i < this->n; i++)
{
y.medicamente[i] = this->medicamente[i];
}
y.medicamente[this->n] = x;
delete[] this->medicamente;
this->medicamente = new Medicament[this->n + 1];
this->n++;
for (int i = 0; i < this->n; i++)
{
this->medicamente[i] = y.medicamente[i];
}
}
Medicament operator[](int i)
{
if (i >= 0 && i < this->n)
{
return this->medicamente[i];
}
}
friend class RetetaCompensata;
virtual float getValoare()
{
float sum = 0;
for (int i = 0; i < this->n; i++)
{
sum=sum+this->medicamente[i].getPret();
}
return sum;
}
friend ifstream& operator>>(ifstream& consola, Reteta& x)
{
char aux[30];
float z;
consola >> x.n;
if (x.medicamente)
delete[] x.medicamente;
x.medicamente = new Medicament[x.n];
for (int i = 0; i < x.n; i++)
{
consola >> aux >> z;
Medicament m(aux, z);
x.medicamente[i] = m;
}
return consola;
}
};
class RetetaCompensata : public Reteta{
private:
float procentCompensat;
public:
RetetaCompensata(float procent)
{
this->procentCompensat = procent;
}
RetetaCompensata(Reteta r, float procent)
{
this->procentCompensat = procent;
this->n = r.n;
this->medicamente = new Medicament[r.n];
for (int i = 0; i < r.n; i++)
{
this->medicamente[i] = r.medicamente[i];
}
}
float getValoare()
{
float sum = 0;
sum = this->procentCompensat*this->getValoare();
return sum;
}
friend ostream& operator<<(ostream& consola, RetetaCompensata &x)
{
consola << "**Procent compensat: " << x.procentCompensat << endl;
consola << "Numar de medicamente: " << x.n << endl;
consola << " -->Lista Medicamente<-- " << endl;
for (int i = 0; i < x.n; i++)
{
consola << x.medicamente[i] << " ";
}
return consola;
}
};
void main()
{
//1
Medicament nurofen("Nurofen", 11.25f);
Medicament aspirina = nurofen;
aspirina.setDenumire("Aspirina");
aspirina.setPret(4.5f);
Medicament bixtonim("Bixtonim", 8.2f);
Medicament temp;
temp = nurofen;
cout << temp << endl;
cout << nurofen << endl;
cout << aspirina << endl;
//2
Medicament medicamente[] = { aspirina, nurofen };
Reteta r0(medicamente, 2);
cout << r0 << endl;
//3
Reteta r1;
r1.adaugaMedicament(nurofen);
r1.adaugaMedicament(aspirina);
for (int i = 0; i < r1.getN(); i++)
{
cout << r1[i] << endl;
}
//4
RetetaCompensata r2(0.5);
r2.adaugaMedicament(bixtonim);
r2.adaugaMedicament(aspirina);
RetetaCompensata r3(r1, 0.2);
cout << "AFISARE R3" << endl;
cout << r3 << endl << endl;
Reteta* p = &r1;
cout <<"Valoare reteta r1: "<< p->getValoare() << endl;
//5
Reteta r4;
ifstream fisier("retete.txt");
fisier >> r4;
cout << r4 << endl;
//6
cout << endl << "Afisare Lista :" << endl << endl << endl;
list<Reteta> R;
list<Reteta>::iterator it;
R.push_back(r0);
R.push_back(r1);
R.push_back(r3);
R.push_back(r2);
R.push_back(r4);
for (it = R.begin(); it != R.end(); it++)
{
cout << *it << " Valoare Reteta: " << it->getValoare() << endl << endl << endl; // error at this line when I compile
}
}
This is a memory overwrite:
this->denumire = new char[strlen("Fara denumire")];
strcpy(this->denumire, "Fara denumire");
You are not allocating room for the terminating null character:
this->denumire = new char[strlen("Fara denumire") + 1];
strcpy(this->denumire, "Fara denumire");
But why do this when you have std::string available? That alone not only alleviates errors like this, but you don't need to write assignment operators, copy constructor, or destructor for your Medicament class.
The other error is that your Reteta class lacks a copy constructor and assignment operator, thus it is not safely copyable due to the Medicament* member. You are then using this class as a type in std::list<Reteta>.
Since Reteta is not safely copyable, and std::list makes copies, you enter the world of undefined behavior. Thus you must provide appropriate copy / assignment operators for the Reteta class.

Errors within Main program using classes

I just have a few errors of the same type in my main program. My college professor is not answering my emails so I have to resort to asking you guys. In my main program I have several errors somewhat similar to this: "request for member which is of non-class type." Program01 is basically testing every function in ListType.h, OListType.h, and UListType.h to make sure everything works correctly. Any help you can provide in a timely fashion will be appreciated.
Here is ListType.h:
#ifndef LISTTYPE_H_INCLUDED
#define LISTTYPE_H_INCLUDED
#include <iostream>
class ListType {
public:
ListType(size_t=10);
ListType(const ListType&);
virtual ~ListType();
virtual bool insert(int)=0;
virtual bool eraseAll();
virtual bool erase(int)=0;
virtual bool find(int) const=0;
size_t size() const;
bool empty() const;
bool full() const;
friend std::ostream& operator << (std::ostream&, const ListType&);
const ListType& operator= (const ListType&);
protected:
int *items;
size_t capacity;
size_t count;
};
#endif // LISTTYPE_H_INCLUDED
Here is ListType.cpp:
#include "ListType.h"
ListType::ListType (size_t a) {
capacity = a;
count = 0;
items = new int [capacity];
}
ListType::ListType(const ListType& newlist) {
capacity = newlist.capacity;
count = newlist.count;
items = new int [capacity];
for (size_t i = 0; i < count; ++i)
items[i] = newlist.items[i];
}
ListType::~ListType() {
delete [] items;
}
bool ListType::eraseAll() {
count = 0;
return 0;
}
size_t ListType::size() const {
return (count);
}
bool ListType::empty() const {
return (count == 0);
}
bool ListType::full() const {
return (count == capacity);
}
std::ostream& operator << (std::ostream& out, const ListType& my_list) {
if (!my_list.empty()) {
for (size_t i = 0; i < my_list.count; ++i){
out << my_list.items[i] << ',';
}
}
return out;
}
const ListType& ListType::operator= (const ListType& rightObject) {
if (this != & rightObject) {
delete [] items;
capacity = rightObject.capacity;
count = rightObject.count;
items = new int[capacity];
for (size_t i = 0; i < count; ++i) {
items[i] = rightObject.items[i];
}
}
return *this;
}
Here is UListType.h:
#ifndef ULISTTYPE_H_INCLUDED
#define ULISTTYPE_H_INCLUDED
#include <iostream>
class UListType: public ListType {
public:
UListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // ULISTTYPE_H_INCLUDED
Here is UListType.cpp:
#include "ListType.h"
#include "UListType.h"
UListType::UListType (size_t c): ListType(c) {}
bool UListType::insert(int item) {
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
for (size_t i =0; i < count; ++i){
newitems[i] = items[i];
}
delete [] items;
items = newitems;
}
items[count++] = item;
return true;
}
bool UListType::erase(int item) {
bool result = false;
size_t i=0;
while ( i < count && items [i] != item) {
++i;
}
if (i < count) {
items[i] = items[-- count];
result = true;
}
return result;
}
bool UListType::find(int item) const {
size_t i = 0;
while (i < count && items [i] != item) {
++i;
}
return i < count;
}
Here is OListType.h:
#ifndef OLISTTYPE_H_INCLUDED
#define OLISTTYPE_H_INCLUDED
#include <iostream>
class OListType: public ListType {
public:
OListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // OLISTTYPE_H_INCLUDED
Here is OListType.cpp:
#include "ListType.h"
#include "OListType.h"
OListType::OListType(size_t c): ListType(c) {}
bool OListType::insert(int item) {
size_t i = count;
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
for(size_t j=0; j < count; ++j) {
newitems[j] = items[i];
}
delete [] items;
items = newitems;
}
while (i > 0 && items[i-1] > item){
items[count++] = item;
}
return true;
}
bool OListType::erase(int item) {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
if (found) {
for (i = mid; i < count - 1; ++i) {
items [i] = items [i +1];
}
--count;
}
return found;
}
bool OListType::find (int item) const {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
return found;
}
Here is Program01.cpp:
#include "ListType.h"
#include "UListType.h"
#include "OListType.h"
#include <iostream>
using namespace std;
int main() {
OListType list[5] = {165, 16, 118, 212, 104};
UListType ranlist[10] = {243, 300, 154, 153, 592, 124, 195, 217, 289, 405};
UListType UListAssignmentTest;
OListType OListAssignmentTest;
cout << "The Ordered List before operations:" << endl;
cout << list << endl << endl;
if(list.empty()) **<-- HERE BE THE ERROR**
cout << "The list is empty, therefore it is true.";
else
cout << "The list is full or partially full, therefore it is false";
cout << endl << endl;
if(list.full())
cout << "The list is full, therefore it is true.";
else
cout << "The list is partially full or empty, therefore it is false";
cout << endl << endl;
list.insert(25);
cout << endl << endl;
cout << "The Ordered list after Insert:" << endl;
cout << list << endl << endl;
list.find(25);
cout << endl << endl;
list.find(30);
cout << endl << endl;
list.erase(25);
cout << endl << endl;
cout << "The Ordered List after Erase:" << endl;
cout << list << endl << endl;
cout << "The Unordered List before operations:" << endl;
cout << ranlist << endl << endl;
if(ranlist.empty())
cout << "The list is empty, therefore it is true.";
else
cout << "The list is full or partially full, therefore it is false";
cout << endl << endl;
if(ranlist.full())
cout << "The list is full, therefore it is true.";
else
cout << "The list is partially full or empty, therefore it is false";
cout << endl << endl;
ranlist.insert(25);
cout << endl << endl;
cout << "The Unordered List after Insert:" << endl;
cout << ranlist << endl << endl;
ranlist.find(25);
cout << endl << endl;
ranlist.find(30);
cout << endl << endl;
ranlist.erase(25);
cout << endl << endl;
cout << "The Unordered List after Erase:" << endl;
cout << ranlist << endl << endl;
cout << "Testing Ordered List Assignment Operator" << endl;
OListAssignmentTest = list;
cout << OListAssignmentTest << endl << endl;
cout << "Testing Unordered List Assignment Operator" << endl;
UListAssignmentTest = ranlist;
cout << UListAssignmentTest << endl << endl
cout << "Testing Ordered List Copy Constructor" << endl;
OListType OListVariable = list;
cout << OListVariable << endl << endl;
cout << "Testing Unordered List Copy Constructor" << endl;
UListType UListVariable = ranlist;
cout << UListVariable << endl << endl;
cout << "Testing Erase All for OList" << endl;
list.eraseAll();
cout << "OList values now: " << list.empty() << endl << endl;
cout << "Testing Erase All for UList" << endl;
ranlist.eraseAll();
cout << endl << "UList values now: " << ranlist.empty() << endl;
return 0;
}
OListType list[5] = {165, 16, 118, 212, 104};
This line declares an array of 5 OListType types. This doesn't seem correct.
You want to declare one OLIstType and insert 5 values into it. If not, please clarify what that line is supposed to denote.
Here is probably what you are supposed to do:
OListType list;
list.insert(165);
list.insert(16); // etc...

C++ char vector addition

This is a part of a program that I am writing to compute the addition of two integers as strings. (Writing my own bigInt class).
There appears to be a problem when I am adding the two integers together. Because they are both in vectors of char type, I had to add a '0' to each element of the vector before concatenating it into a string.
However, the results are still not what I am expecting:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string const Number = "1000";
string const Number2 = "1000";
vector<char> reverse;
vector<char> reverse2;
//cout << (rostrNumber[1] - '0') << endl;
cout << "Original Number: " << Number << endl;
reverse.clear();
for (int i = Number.size() - 1; i >= 0; i--)
{
reverse.push_back(Number[i]);
}
cout << "Reversed: " << endl;
cout << reverse[0] << reverse[1] << reverse[2] << reverse[3] << endl;
cout << endl << endl;
reverse2.clear();
{
for (int i = Number2.size() - 1; i >= 0; i--)
{
reverse2.push_back(Number[i]);
}
}
cout << "Adding these two integers" << endl;
vector<char> const rcvN1 = reverse;
vector<char> const rcvN2 = reverse2;
vector<char> Results;
Results.clear();
//Local copies
vector<char> vN1 = rcvN1;
vector<char> vN2 = rcvN2;
int iSize1 = vN1.size();
int iSize2 = vN2.size();
int i, iSize = iSize2;
int iC = 0, iR;
for (i = 0; i<iSize; i++)
{
iR = vN1[i] + vN2[i] + iC;
if (iR > 9)
{
iR -= 10;
iC = 1;
}
else
iC = 0;
Results.push_back(iR);
cout << Results[0] << endl;
}
if (iC > 0)
Results.push_back(iC);
string ostr;
vector<char>::const_reverse_iterator rIter = Results.rbegin();
for (; rIter != Results.rend(); rIter++)
ostr += *rIter +'0';
cout << "Results: " << ostr << endl;
system("PAUSE");
return 0;
}