Trouble with Operator Overloading and the *this Pointer - c++

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;

Related

definition of "operator +=" behaving unexpectedly

Brief
I am defining my own String class. Everything works fine except for my definition of += which I intend to use to concatenate Strings
//expected behaviour
String c = "foo";
String d = "lala";
c+=d;
cout<<c;
Should output:
foolala
I am having an issue with it as it does seem to work correctly except for the last bit where it seems to not be passing the pointer.
Here is the code (I have omitted most of the other definitions as I don't think they are useful for this)
Code
class String{
private:
unsigned int SizeS;
char *Buffer;
public:
String():SizeS(0){}
String(unsigned int i):SizeS(i){Buffer=new char[SizeS];}
String(const char *string)
{
//defines the initialiser
SizeS = strlen(string); //find out the length of the string
Buffer = new char[SizeS]; //allocate space for the entire string+1 for terminator
memcpy(Buffer,string,SizeS); //copy to buffer the whole thing
Buffer[SizeS]=0; //terminate the buffer with an end character
}
char * GetBuffer() const { return this->Buffer; }
String (const String& copied) :SizeS(copied.SizeS)
{
// defines how copying works
Buffer = new char[SizeS];
memcpy(Buffer,copied.Buffer,SizeS);
}
// this is where the issue is ------------------
String* operator += (const String& to_concat)
{
unsigned int newSize = this->SizeS + to_concat.SizeS;
String *p = new String(newSize) ;
memcpy(p->Buffer,this->Buffer,this->SizeS);
memcpy(p->Buffer+this->SizeS,to_concat.Buffer,to_concat.SizeS);
std::cout<<p->Buffer<<std::endl;
return p;
}
// this is where the issue ends ------------------
};
std::ostream& operator<< (std::ostream& stream, const String& other) { stream << other.GetBuffer(); return stream; }
int main()
{
String c="foo";
std::cout<<c<<std::endl;
c += c;
std::cout<<c<<std::endl;
}
Expected Output
foo
foofoo
foofoo
Actual Output
foo
foofoo
foo
Question
What am I doing wrong? From my understanding, I am overwritting the pointer c with the pointer p, but it seems as though c does not change. Why is that ?
Solution
After reading the comments and suggestion I came up with this solution which works.
String& operator += (const String& to_concat)
{
unsigned int newSize = this->SizeS + to_concat.SizeS;
char* p = new char[newSize];
memcpy(p,this->Buffer,this->SizeS);
memcpy(p+this->SizeS,to_concat.Buffer,to_concat.SizeS);
delete[](this->Buffer);
this->Buffer=p;
this->SizeS=newSize;
return *this;
}
Because you didn't write any code to change c.
There is no "pointer c" and, even if there were, you'd not be overwriting it.
Your += creates a new, dynamically allocated string, using the data from the original two strings, then returns a pointer to it which your program then throws away (incidentally, leaking that new string).
Instead of creating and returning p, you should be modifying the buffer in this (then, conventionally, returning *this as a String& to permit chaining).
Also, a += operator should not produce output.
A + operator could work similarly to how you've done it, since they're supposed to produce new objects, but you shouldn't actually use new for that — you'd still have a memory leak. Try to avoid dynamic allocation (though you're going to need to dynamically allocate the buffer that each String's buffer pointer point to).

why subtracting from pointer in this destructor and assignoperator?

Hi I have a test tomarrow and can't figure out why subtraction is made on the pointer before checking if the refcount is 0. I've been searching on google but still cant figure it out. So I'm hoping turning to you guys :) would help.
Easyiest is too just show you the code, I've marked the lines with comments, so here it is:
This is the class StringRep that has pointers to it for counting pointerref to it,
struct StringRep{
int size; // amount of chars incl. EOL \0-tecken
char* chars; // Pointer to char
int refCount; // Amount of String-variables
};
And this is class String that uses the StringRep,
class String{
public:
String(char* str);
String(const String& other);
~String();
const String& operator=(const String& rhs);
char get(int index) const { return srep->chars[index]; }
void put(char ch, int index);
private:
StringRep* srep;
};
String::String(const String& other):srep(other.srep){
srep->refCount++;
}
String::~String(){
if (--srep->refCount == 0){ //why --srep here?
delete [] srep->chars;
delete srep;
}
}
const String& String::operator=(const String& rhs){
if (srep != rhs.srep){
if (--srep->refCount == 0){ //why --srep here?
delete [] srep->chars;
delete srep;
}
srep = rhs.srep;
srep->refCount++;
}
return *this;
}
void String::put(char ch, int index){
if (srep->refCount > 1){ //Why not --srep here?
StringRep* tmpRep = new StringRep;
tmpRep->refCount = 1;
tmpRep->size = srep->size;
tmpRep->chars = new char[tmpRep->size];
std::strcpy(tmpRep->chars, srep->chars);
--srep->refCount;
srep = tmpRep;
}
srep->chars[index] = ch;
}
This is all info I have on the example question for the test, I know that --spek points to the object before spek, but cant figure out the logic behing checking if what is pointed at before now is 0 then its okey to delete, or to copy, but why? As I said I've searched the webb and have found some answers to help me understand the functions of the pointer and the subtraction etc, it more the logic that is confusing.
Best regards
Because of operator precendence, --srep->refCount is not decrementing srep, but the refCount member.
So, the code is decrementing the refCount, and if it comes down to 0, it can assume that the last reference to the object is being destroyed.
--srep->refCount
is parsed as
--(srep->refCount)
because prefix decrement has lower priority than -> (however, postfix decrement has the same priority as ->). Always use parens in your own code!

Error in C++ code when overloading operators

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).

Operator Overloading: C++

I have a question about Operator Overloading in C++.
For an assignment, I have to write a class which encompasses an array, sort of like the ArrayList in Java.
One of the things I have to do is keep track of the size of the array. Size is the amount of elements included, whereas capacity is the maximum amount which CAN be included before the class has to expand the array.
Client code specifies the size when they call the constructor. However, when new elements are added, I have to figure out a way to change the size.
My teacher said something about being able to overload an operator for different sides of an equality. Is this a real thing, or did I misunderstand her? If this works, it would be the optimal solution to my problem.
My current overloading for the [] operator is:
int & ArrayWrapper::operator [] (int position){
if(position == _size){
if(_size == _capacity){
changeCapacity(_capacity+10);
}
}
return _array[position];
}
This works fine for retrieval, but I'd like to have it so that if someone calls it from the left hand side of a '=' then it checks to see if it needs to expand the size or not.
EDIT: If this isn't a real thing, can anyone think of a different solution to the problem? One solution I thought of is to have the getSize() method just go through the entire array every time it is called, but I'd really rather not use that solution because it seems cheesy.
EDIT: For clarification, I'm not asking whether or not my expansion of an array works. I need to add 1 to size every time a new element is added. For example, if the client creates an array of size 15 and capacity 25, and then tries to add something to Array[15], that SHOULD increase the size to 16. I was wondering if there was a way to do that with overloading.
A simple approach, which doesn't quite do what you want, is to overload on whether the array is const or mutable.
This doesn't distinguish between whether the array is being used on the left-hand side of assignment (as a lvalue) or on the right (as a rvalue); just on whether it's allowed to be modified or not.
// Mutable overload (returns a mutable reference)
int & operator[](size_t position) {
if (position >= _size) {
if (position >= _capatity) {
// increase capacity
}
// increase size
}
return _array[position];
}
// Const overload (returns a value or const reference)
int operator[](size_t position) const {
if (position >= _size) {
throw std::out_of_range("Array position out of range");
}
return _array[position];
}
If you really want to tell whether you're being assigned to or not, then you'll have to return a proxy for the reference. This overloads assignment to write to the array, and provides a conversion operator to get the value of the element:
class proxy {
public:
proxy(ArrayWrapper & array, size_t position) :
_array(array), _position(position) {}
operator int() const {
if (_position >= _array._array._size) {
throw std::out_of_range("Array position out of range");
}
return _array._array[_position];
}
proxy & operator=(int value) {
if (_position >= _size) {
if (_position >= _capatity) {
// increase capacity
}
// increase size
}
_array._array[_position] = value;
return *this;
}
private:
ArrayWrapper & _array;
size_t _position;
};
You probably need to declare this a friend of ArrayWrapper; then just return this from operator[]:
proxy ArrayWrapper::operator[](size_t position) {
return proxy(*this, position);
}
This approach is fine. There's an error in the code, though: what happens if someone calls that operator with a position that's equal to the current size of the array plus 100?
The question is whether you really want different behavior depending on
which side of the = you are. Your basic idea will work fine, but will
expand the array regardless of the side you're on, e.g.:
ArrayWrapper a(10);
std::cout << a[20] << std::end;
will result in expanding the array. Most of the time, in such cases,
the preferred behavior would be for the code above to raise an exception,
but for
ArrayWrapper a(10);
a[20] = 3.14159;
to work. This is possible using proxies: first, you define double
ArrayWrapper::get( int index ) const and void ArrayWrapper::set( int
index, double newValue ); the getter will throw an exception if the
index is out of bounds, but the setter will extend the array. Then,
operator[] returns a proxy, along the lines of:
class ArrayWrapper::Proxy
{
ArrayWrapper* myOwner;
int myIndex;
public:
Proxy( ArrayWrapper& owner, int index )
: myOwner( &owner )
, myIndex( index )
{
}
Proxy const& operator=( double newValue ) const
{
myOwner->set( myIndex, newValue );
}
operator double() const
{
return myOwner->get( myIndex );
}
};
In case you're not familiar with the operator double(), it's an
overloaded conversion operator. The way this works is that if the
operator[] is on the left side of an assignment, it will actually be
the proxy which gets assigned to, and the assignment operator of the
proxy forwards to the set() function. Otherwise, the proxy will
implicitly convert to double, and this conversion forwards to the
get() function.

Not copying char arrays, function swap doesnt compile correctly and stringPtr is not modified

//In header file: class definition:
class myString
{
public:
myString(void);
myString(const char *str);
myString(const myString &); //copy constructor
~myString(void); //destructor
void swap(myString &from);
private:
char *stringPtr;
int stringLen;
};
//in cpp file, defining them member functions
myString::myString(const char *str)
{
stringLen = strlen(str);
stringPtr = new char[stringLen+1];
strcpy(stringPtr,str);
cout << "constructor with parameter called"<<endl;
}
myString::myString(const myString &str)
{
stringPtr = new char[str.stringLen +1];
strcpy(stringPtr,str.stringPtr);
cout << "copyconstructor"<<endl;
}
void myString::swap(myString &from)
{
myString buffer(from);
int lengthBuffer = from.stringLen;
from = new char[stringLen+1];
from.stringLen = stringLen;
strcpy(from.stringPtr, stringPtr);
stringPtr = new char[lengthBuffer+1];
stringLen = lengthBuffer;
strcpy(stringPtr,buffer.stringPtr);
}
You can't modify a reference. Even if you replace it with a pointer modifying a pointer will not modify an object pointed to. Instead you need to work through the reference - just swap the fields.
void myString::swap(myString &from)
{
std::swap( stringLen, from.stringLen );
std::swap( stringPtr, from.stringPtr );
}
the above is using std::swap() as suggested by user sbi in comments. This is completely equivalent to the following (just for illustration, don't reinvent STL):
void myString::swap(myString &from)
// First remember own length and pointer
const int myOldLen = stringLen;
char* myOldPtr = stringPtr;
// now copy the length and pointer from that other string
stringLen = from.stringLen;
stringPtr = from.stringPtr;
// copy remembered length and pointer to that other string
from.StringLen = myOldLen;
from.StringPtr = myOldPtr;
// done swapping
}
Both will work even when called fro self-swapping:
myString string;
string.swap( string );
You have already gotten a few good answers concerning the errors in you myString::swap() function. Yet, I'd like to add another one. There's some many things wrong with that function, I first found it hard to think of where to begin. But then I realized that you fail on some fundamental issue which I'd like to point out:
As a convention, a function called swap is expected to perform its task
in O(1)
without ever throwing an exception.
(Yes, I know, there are exceptions: std::tr1::array<>::swap(). But those should be very well justified.) Your implementation fails on both accounts. It is O(n) (strcpy) and might throw an exception (new) -- and it does so unnecessarily and without justification.
When you look at myString, you'll see that it only has two pieces of member data, which both are of built-in type. That means swapping two objects of this class is really simple to do while keeping to the conventions mentioned above: just swap the member data. That's as simple as calling std::swap on them:
void myString::swap(myString &from)
{
std::swap(this->stringPtr,from.stringPtr);
std::swap(this->stringLen,from.stringLen);
}
This is will never fail (swapping two pointers and two integers cannot fail), executes in O(1), is very easy to understand (well, once you get a grip on that swapping, anyway; it is an idiomatic form of implementing a class-specific swap function), and consists of two lines of code calling something well-tested in the standard library instead of 8 lines of code doing error-prone (and, in your case, erroneous) manual memory management.
Note 1: Once you've done this, you should specialize std::swap to call your implementation for your class:
namespace std { // only allowed for specializing function templates in the std lib
template<>
inline void std::swap<myString>(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
Note 2: The best (simple, exception-safe, and self-assignment-safe) way to implement assignment for your class is to use its swap:
myString& myString::operator=(const myString& rhs)
{
myString tmp(rhs); // invoke copy ctor
this->swap(tmp); // steal data from temp and leave it with our own old data
return *this;
} // tmp will automatically be destroyed and takes our old data with it
from = new char[stringLen+1]; should be from.stringPtr = new char[stringLen+1]; . Also remember to free the previously allocated memory before allocating new one.
Look closely at the line
from = new char[stringLen+1];
It is the same as
from = MyString(new char[stringLen+1]);
so your constructor of MyString get uninitialized array of chars. Then you trying to get the length of the string, but strlen just looping through chars of the string looking for 0 char. As we don't know what content uninitialized array of chars might have, we don't know what length strlen could return. It can even go further than array boundary and crash your program with segfault. But I can say for sure, after that there's not enough space in from.stringPtr to hold the string you want to copy in it.
So, use from.stringPtr = new char[stringLen+1]; or better from = MyString(*this); since you have copy constructor already.