Error in C++ code when overloading operators - c++

I'm trying to overload the '+' and '=' operators in my code, but I keep getting a run time error and the program crashes when running using VS2012 but runs perfectly in borland C 3.1.
Here's my code:
class employee{
int eid;
long esalary;
char * ename;
static char company_name[20];
static int emp_count;
public:
static char * getcompanyname(){
return company_name;
}
static int getempcount(){
return emp_count;
}
void set(int empid);
void set(long empsalary);
void set(char empname[]);
int getid();
long getsalary();
char * getname();
employee(int empid=0,long empsalary=0,char empname[]="NA"){
eid=empid;
esalary=empsalary;
ename=new char[strlen(empname)+1];
strcpy(ename,empname);
emp_count++;
}
employee(employee &ref){
eid=ref.eid;
esalary=ref.esalary;
ename=new char(strlen(ref.ename)+1);
strcpy(ename,ref.ename);
}
~employee(){
delete(ename);
}
employee operator+(employee &ref){
employee temp(*this);
temp.esalary=esalary+ref.esalary;
return(temp);
}
employee& operator= (employee &ref){
eid=ref.eid;
esalary=ref.esalary;
return * this;
}
}e1,e2,emp;
then in main:
emp=e1+e2;

To be honest, your code is invalid. It should not even compile, since it violates the reference binding rules: the + operator returns a temporary object, which cannot be passed through a non-const reference to the = operator. If you managed to compile this code, it simply means that your compiler(s) accepts it as an "extension" of the language.
To fix that specific error you have to add a bunch of const qualifiers to your declarations
employee operator +(const employee &ref) const {
employee temp(*this);
temp.esalary = esalary + ref.esalary;
return temp;
}
employee& operator =(const employee &ref){
eid = ref.eid;
esalary = ref.esalary;
return *this;
}
This will make your code valid from the C++ point of view, but it probably won't fix the crash, since the reason for the crash must be elsewhere.
Here's your crash-causing error: in the copy-constructor you did this
ename=new char(strlen(ref.ename)+1);
When you allocate an array with new, you have to use [] brackets, not ()
ename = new char[strlen(ref.ename) + 1];
You did it correctly in your first constructor, but then you for some reason used () instead of [] in your copy constructor. () in this context mean something completely different: it allocates a single char and initializes it to strlen(ref.ename) + 1 value.
BTW, is there a reason you are not copying ename in the copy-assignment operator?
Also, memory allocated with new[] must be freed with delete[]. Not with delete, but with delete[]. This is what your destructor should look like
~employee() {
delete[] ename;
}
Finally, you might be much better off using std::string for storing ename, instead of relying on raw memory management. (Unless you were specifically asked to do it that way).

Related

Address of stack memory returned when overloading operator [ ]

I'm encountering some issues with overloading the [] operator for a problem in class. This is the function for the overloading:
const char* Person::operator[](const char* str)
{
if (strcmp(str, "name") == 0)
return reinterpret_cast<const char *>atoi(name);
if (strcmp(str, "age") == 0)
{
char temp[4];
_itoa(age, temp, 10);
//cout << temp;
return temp;
}
}
The class defition looks like this
class Person
{
private:
const char* name;
unsigned int age;
double height;
int gradeNo;
int grades[10];
public:
Person();
Person(const char* name, int age, double height);
void addGrade(int grade);
const char* operator [] (const char* str);
operator int();
};
The problem I'm getting is with the return temp; line from the operator overload function. CLion returns the following warning: Address of stack memory associated with local variable 'temp' returned
Sure enough, when trying to use the operator, the value returned is a memory address. How can I go about fixing this? Is it related to the return type of the function?
You are taking an address to a temporary (that is located on the stack), that will leave the returned pointer dangling almost immediately.
I would very strongly suggest using std::string for strings, do not write C++ just as C with classes.
Then return by std::string by value here. Bad C-like alternative is to allocate the string on the heap and return that, preferably as std::unique_ptr at least.
EDIT after the comment below:
Since you are required to convert an integer to string and return the value, you cannot return a temporary variable, the result must outlive the method. There are basically two bad options:
Make temp static, this way the pointer remains valid. Downside is the function is no longer re-entrant. This is safer because it won't leak.
const char* foo(int age){
static char temp[4];
_itoa(age, temp, 10);
return temp;
}
Return a heap allocated string. Big danger is that you are leaving the user to deallocate it:
const char* foo(int age){
char* temp = new char[256];
_itoa(age, temp, 10);
return temp;
}
I believe you also have a typo in your code:
return reinterpret_cast<const char *>atoi(name);
The atoi should not be there, right?reinterpret_cast should not be needed.

One warning and main() returned garbage value

Multiple students can associate with a single Department and single student can
associate with multiple Departments, but there is no ownership between the objects
and both have their own lifecycle. Both can create and delete independently.
WAP in C++ to model the relationships.
I have implemented this code as follows
#include<iostream>
#include<cstring>
using namespace std;
class Student
{
char* name_p;
public:
Student(char *sName)
{
cout<<"Student constructor called\n";
name_p=new char(sizeof(strlen(sName)));
name_p=sName;
}
~Student()
{
cout<<"Student destructor called\n";
delete name_p;
};
char* sName()
{
return name_p;
}
};
class Department
{
char* name_p;
public:
Department(char *dName)
{
cout<<"Department destructor called\n";
name_p=new char(sizeof(strlen(dName)));
name_p=dName;
}
~Department()
{
cout<<"Department destructor called\n";
delete name_p;
}
char* dName()
{
return name_p;
}
};
class Course
{
Student* std_p;
Department* dept_p;
char* courseName_p;
static unsigned int index;
static Course *courseList_p[4];
public:
Course(char* crseName,Student* student,Department* dept)
{
cout<<"Course constructor called\n";
std_p=student;
dept_p=dept;
if(index<4)
{
courseName_p=new char(sizeof(strlen(crseName)));
courseName_p=crseName;
courseList_p[index]=this;
++index;
}
else
{
cout<<"Cannot accomodate any more Course\n";
}
};
~Course()
{
cout<<"Course destructor called\n";
delete courseName_p;
};
static char* findStudent(char *crseName, char* deptName)
{
for(int i=0; i<index; i++)
{
if ( (courseList_p[i]->getCourseName() == crseName) &&
(courseList_p[i]->getDeptName() == deptName) )
{
return(courseList_p[i]->getStdName());
}
}
}
char* getStdName()
{
return std_p->sName();
};
char* getDeptName()
{
return dept_p->dName();
};
char* getCourseName()
{
return courseName_p;
};
};
unsigned int Course::index =0;
Course* Course::courseList_p[4]={0,0,0,0};
int main()
{
int i;
cout<<"\nExample of Association class\n";
cout<<"-----------------------------------\n\n";
cout<<"We have got 4 students\n";
Student *studentNames[4] = {new Student("Meera"), new Student("Moina"), new Student("Teena"), new Student("Mridula")} ;
cout<<"\n";
cout<<"We have got 2 Departments\n";
Department *departNames[2] = {new Department("Mathematics"), new Department("ComputerSceince")} ;
cout<<"\n";
cout<<"Here class Course Associates Student and Department, with a Course name\n";
Course course1("DataStructure",studentNames[0], departNames[1]);
Course course2("Maths",studentNames[3], departNames[0]);
Course course3("Geometry",studentNames[2], departNames[0]);
Course course4("CA",studentNames[1], departNames[1]);
cout<<"\n";
cout<<"Finding a Student using Course and Department\n";
cout<<"Student who has taken Maths Course in Mathematics Department is:"<<Course::findStudent("Maths", "Mathematics")<<endl;
cout<<"\n";
cout<<"Deletion of objects\n\n";
for(i=0;i<4;i++)
{
delete studentNames[i];
}
cout<<"\n";
for(i=0;i<2;i++)
{
delete departNames[i];
}
cout<<"\n";
return 0;
}
The code is showing warnings in main function i.e. ISO C++ forbids converting a string constant to char* and also the main() function is not returning 0 but a garbage value. Please help me in rectify these errors and warnings.
Also I don't want to use this pointer in class course, can I implement the code without using this pointer.
There are a couple of problems with your code. Mostly they are related to the use of char* instead of string. I'm amazed to see that some teacher still are found of this practice.
c-string allocation problems
The first problem causes memory corruption. This could explain that your main() returns garbage instead of 0. For example:
name_p=new char(sizeof(strlen(dName))); // OUCH!!!
In the statement you allocate it wrong. If you want to allocate an array, you must use new[...]. Moreover, keep in mind that a c-string allways needs 1 char more for the trailing null. So it should be:
name_p=new char[strlen(dName)+1];
would already improve the situation.
Last but not the least, if you allocate an array you must delete an array with delete[]
c-string copying issue
Then, you can copy C++ string with an assignment operator just as in:
name_p=sName; // OUCH
However, for char*, this just overwrites the pointer that new returned and you are not sure that the c-string it points to will still be valid when it's used.
If you want to assign a c-string, you need to go for:
strcpy (name_p, sName); // C-style
copy (sName, sName+strlen(sName)+2, name_p); // Safer C++ alternative
c-string comparison issue
Suppose you have two pointers to c string, say pa and pb. Comparing the pointers looks at the memory address, not at the content. So yu could have two identical strings but the comparison could nevertheless fail. THis kind of comparison would work perfectly well for c++ string, but for cstring, you need to to
strcmp(pa, pb)==0 // instead of pa == pb
c-strings in classes and structures
Whenever you have some pointers that you allocate in a class, you need to think of the rule of 3. Meaning that you'd need to add a copy constructor and an assignment operator. Fortunately, at first sight it seems that you don't need them here. Of couse, if you'd use c++ string you wouldn't have to worry about such details.
c-string conversion issues?
ANother issue in your code is the use of string literals with constructors. For example:
new Student("Meera").... // c-string literals (constant)
Student(char*...) // constructor using a c-string pointer (non constant)
You can easily get rid of this complaint, by making the constructor's pointer argument as constant:
Student(const char *sName)...
The same applies to function arguments, such as in find.
Other problems
The static member findStudent() works well, but only if a result is found. If nothing is found, it's UB, since there is no return statement (put a return nullptr; at the end of this function?)
Moreover, the wya you use this function, directly printing its result is dangerous, because dereferencing an invalid pointer will lead to UB.
Here the corrected code. It compiles and seem to run. I didn't analyse for more issues.

c++ no matching constructor?

I have to create an own string class for a university project, my code so far looks like(I only show the relevant parts):
class SuchString
{
char* str;
size_t siz;
public:
SuchString(char* a);
~SuchString();
SuchString(SuchString& a);
SuchString operator+(const SuchString& a) const;
...
...
};
As you can see I have a constructor for char* types, implemented as:
SuchString::SuchString(char* a)
{
siz = strlen(a);
str = new char[siz];
strcpy(str, a);
}
The problem is with my operator+ function:
SuchString SuchString::operator+(const SuchString &a) const
{
return SuchString(strcat(str, a.str));
}
I get the following error message:
No matching constructor for initialization of 'SuchString'
As far my understanding goes, the strcat function should return with a char*, and I have a constructor for that type.
I get the same error message for the following:
SuchString SuchString::operator+(const SuchString &a) const
{
char* lel = strcat(str, a.str);
return SuchString(lel);
}
And again, the same thing happens. I expected that the code SuchString(lel) would create a temporary variable, so the function can return with it, just as in the previous example.
Any help is appreciated.
ps: I know it's absolute nonsense to create a string class like this, but this is some small project for university.
SuchString(SuchString& a); takes a non-const reference as a parameter, so passing it temporaries is not doable. What you probably want is
SuchString(const SuchString& a);
because when you return by value, a copy is made - i.e.:
return SuchString(lel);
will create a temporary SuchString which is then copied and returned. In theory, that is, because in practice the copy is most likely optimized out.

Trouble with Operator Overloading and the *this Pointer

I'm working on operator overloading for a self made dynamic array class. I'm also trying to learn how to use the *this pointer but it's not going so well. Below are the parts of the class and my code that I thought were needed to explain the issue.
I don't understand why I can't call a member function on the *this pointer when the *this pointer is pointing to the left side of the + equation.
Here is the stub driver that is calling the + operator:
<< and >> are already overloaded and working.
cout << "Please enter a word to add:";
string theWord;
cin >> theWord;
//add word
array1 = array1 + theWord;
cout << "array1: " << array1 << endl;
Here is the main code:
class DynamicArray
{
public:
//constructor
DynamicArray(int initialcapacity = 10);
//copy constructor
DynamicArray(const DynamicArray& rhs);
//destructor
~DynamicArray();
//operator+ - add a string
DynamicArray operator+(const string& rhs) const;
//operator+ - concatenate another DynamicArray
DynamicArray operator+(const DynamicArray& rhs) const;
//change the capacity of the DynamicArray to the newCapacity -
// may reduce the size of the array - entries past newCapacity will be lost
void resize(int newCapacity);
private:
string* mWords;//pointer to dynamic array of strings
int mNumWords;//the current number of words being kept in the dynamic array
int mCapacity;//the current capacity of the dynamic array (how many strings could fit in the array)
//display all the contained strings (each on a newline) to the output stream provided
void displayContents(ostream& output) const;
//add all the strings contained in the input stream to the dynamic array - resize if necessary
//return how many words are added to the array
int addWords(ifstream &input);
//add a single word to the dynamic array - resize if necessary
void addWord(const string& word);
};
//add a single word to the dynamic array - resize if necessary
void DynamicArray::addWord(const string& word)
{
if (mNumWords >= mCapacity)//need more space?
{
resize(mCapacity + 1);
}
mWords[mNumWords] = word;
mNumWords++;
}
This is the function I'm currently working on
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
//this doesn't work, why doesn't it, how should/do I use the
//this pointer properly
this.addWord(rhs);
return *this;
}
In addition to using this. instead of this->, you have defined operator+ as a const member function. This means that no members can be mutated, and no calls to non-const member function functions are to be performed. Your addword function is non-const. That's the reason for the error -- you are violating const correctness.
Also, why are you mutating the array for merely calling operator + in your code? That operator shouldn't need to change any aspect of the current object. I can understand operator += mutating the object, but not operator +.
What you should do is write an operator += first. This operator can mutate the current object, since that is the semantics of += (change the current object). Then operator + can be written this way:
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
DynamicArray temp = *this;
temp += rhs;
return temp;
}
This is assuming you have a working copy constructor. In the example above, you are mutating a temporary, calling += on the temporary, and returning the temporary. The this object does not change.
Here is what your operator += should look like:
DynamicArray& DynamicArray::operator+=(const string& rhs)
{
this.addWord(rhs);
return *this;
}
Now operator += becomes non-const because the intention of += is to change the current object. Note that the return value is a reference to the current object. This now works in concert with the operator + above.
Your operator+ has to be non-const since you want to change the state of the object on each it is invoked. Also you don't have to write
this->addWord( rhs); // correct but not needed
because use of method inside a class member function is called on this pointer implicitly. Given this, you may write:
DynamicArray DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
return *this;
}
You can also implement this operator as void:
void DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
}
and use it this way:
array1 + theWord;

C++ Writing Object to Binary File

Problem:
Error: The "&" operator can only be applied to a variable or other l-value.
What I've tried:
dynamic_cast<char*>(e)
reinterpret_cast<char*>(e)
static_cast<char*>(e)
(char*) e
What I'm trying to do:
Write the array e.data (private) to a binary file.
Notes:
e.getSize() returns number of elements in array
e[] returns Employee object.
Code:
fstream fout;
fout.open(filename.c_str(), ios::out|ios::binary);
if(fout.good())
{
for(int i=0;i<e.getSize();i++)
{
fout.write((char*)&e[i], sizeof(e[i]));
}
}
fout.close();
Employee.h
class Employee {
friend std::ostream& operator<<(std::ostream&, const Employee &);
private:
int id;
char name[50];
char address[100];
char phone[20];
char department[100];
int salary;
public:
Employee();
~Employee();
Employee(int,char[],char[],char[],char[],int);
bool operator==(Employee&);
};
I'm lost at what to do, from what I remember fout.write((char*)&e[i], sizeof(e[i])); is how to write to binary files.
Edit:
e is declared like so:
MYLIB::Bucket<Employee> e;
template <class T>
class Bucket {
private:
T* bkt;
int size;
int capacity;
static const int stepsize = 10;
public:
Bucket();
~Bucket();
void push_back(const T&);
T operator[](int);
int getSize();
int getCapacity();
};
Edit 2:
fout.write(reinterpret_cast<char*>(e[i]), sizeof(e[i])); gives me line 122: Error: Using reinterpret_cast to convert from ? to char* not allowed. (Line 122 is the line just quoted)
Edit 3:
tempemp = e[i];
fout.write((char*)(&tempemp), sizeof(e[i]));
Compiles but gives a segmentation fault, I'll investigate why.
Compiles, the segmentation fault looks unrelated.
MYLIB::Bucket<Employee> e;
this seems to be a container. e[i] gives you an Employee by value. you need to get this object's address using &e[i] but you can'd do that since it's an r-value so you need to copy it to a non r-value:
Employee copye = e[i];
fout.write((char*)&copye, sizeof(e[i]));
Should work.
On a side note, this all looks like terrible code and I don't envy whoever needs to maintain or read it. A few points:
you should not be using the binary format of the in-memory object as your serialization format. Use a proper serialization format like protobuf or xml or json
Why pull your own strange containers when you can use std::vector std::list ? re-inventing the wheel is always bad
returning an element by value from a container creates copies which degrade performance.
I think that
T operator[](int);
is returning a temporary object that must be bound to something before an address can be taken
const Employee& emp = e[i];
fout.write((char*)&emp, sizeof(emp));
might work, assuming this answer is correct that taking a reference extends the life of a temporary object
An alternative might be to return a reference to the object, which would remove the creation of temporary objects
const T& operator[](int);