I've been looking around for quite some time and think I have most of the pieces together but my code still won't work...
I have a map,
map<Number, Entry> chainList;
and a class Number and Entry, the Entry we wont worry about for now as I'm pretty sure that half works correct
in Number.h
class Number
{
public:
//Public Functions
//Constructor/Destructor
Number(int len);
Number(string copy);
Number(const unsigned char *copy, int len);
Number(const Number& in);
~Number();
.......
.......
friend void swap(Number& first, Number& second);
bool operator<(const Number& rhs) const;
Number& operator=(Number &rhs);
private:
//our binary number array
unsigned char *num;
//hold the length used, and maxsize of the array
int length;
};
then,
//in Number.cpp
Number::~Number()
{
delete [] num;
}
Number::Number(const Number& in)
{
length = in.length;
num = (unsigned char *) calloc(length, sizeof(unsigned char));
for (int i = 0; i < length; i++)
{
num[i] = in.num[i];
}
}
bool Number::operator<(const Number& rhs) const
{
if (this -> length > rhs.length)
{
return false;
}
for (int i = 0; i < this -> length; i++)
{
if (this -> num[i] > rhs.num[i])
{
return false;
}
else if (this -> num[i] < rhs.num[i])
{
return true;
}
}
return false;
}
void swap(Number& first, Number& second)
{
// enable ADL (not necessary in our case, but good practice)
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.length, second.length);
swap(first.num, second.num);
}
Number& Number::operator=(Number &rhs)
{
swap (*this, rhs);
return *this;
}
however when I try and insert an item into the map I get a seg fault....
in Database.cpp
....
chainList.insert(pair<Number, Entry>(*(tempEntry -> msgHash), *tempEntry));
.....
where tempEntry -> msgHash is a Number* - dynamically allocated
what could my issue be? another option is I have a function that typecasts and returns a c++ string, my question is will the std::less_than function work with null characters in the middle of the statement, I know it works in lexigraphical order but is it up to the first null?
I think the problem is in operator<():
if (this->length > rhs.length)
return false;
for (int i = 0; i < rhs.length; i++)
....
See? If rhs.length is greater than this->length you go on and compare the bytes. But you compare up to rhs.length bytes, and that might overflow this->num, as this->length is less or equal to rhs.length.
I'm not sure if you need a specific sorting order, but I would do something like:
if (this->length > rhs.length)
return false;
if (this->length < rhs.length)
return true;
for (int i = 0; i < rhs.length; i++)
....
Now, when you reach the loop you are sure that both arrays are the same length.
UPDATE:
You have another important issue in operator=(Number &rhs). This operator should never modify the right-hand-side operator. So it should be operator=(const Number &rhs) or operator=(Number rhs), but never a non-const reference, as yours is.
You are trying to implement the copy-and-swap idiom. You got it almost right, the proper way is:
Number& Number::operator=(Number rhs)
{
swap (*this, rhs);
return *this;
}
UPDATE #2:
You are allocating your array with calloc() but freeing it with delete[]. That is undefined behaviour. Memory allocated with calloc() is freed with free(), and memory allocated with new[] is freed with delete[].
My advice is to use std::vector<unsigned char> to hold dynamic arrays, and avoid all the this->length, delete[], etc. Just do std::swap() on the vectors and it's done.
Related
Why is bool casting being called ?
The problem appears when the constructor Set result(*this) is called. I expect it to use the Copy Constructor, instead it casts *this to bool and uses it as an int for the constructor.
How to fix it to use the copy constructor?
Set Set::operator+(const Set& rhs)const
{
Set result(*this);
for (unsigned int i = 0; i < rhs.getSize(); i++)
{
result.add(rhs[i]);
}
return result;
}
Set::operator bool()const
{
return !!(*this);
}
Set::Set(size_t capacity)
{
data = new int[capacity];
size = 0;
this->capacity = capacity;
}
void Set::copy(const Set& copied)
{
size = copied.getSize();
capacity = copied.getCapacity();
if (data != nullptr)
delete[]data;
data = new int[capacity];
for (unsigned int i = 0; i < size; i++)
data[i] = copied.getAt(i);
}
Set::Set(Set& copied)
{
copy(copied);
}
Set& Set::operator=(const Set& copied)
{
if (this != &copied)
copy(copied);
return *this;
}
int& Set::getAt(unsigned int idx)const
{
if (idx < 0 || idx >= size)
throw "Invalid index\n";
return data[idx];
}
bool Set::operator !()const
{
if (size == 0)
return true;
return false;
}
The argument for your copy constructor Set::Set(Set& copied) is not a const reference. The operator Set Set::operator+(const Set& rhs)const is const so this is a const Set * and *this is a const Set. Since you cannot pass a const T to a T& argument (it would discard the const) you may not make use of the copy constructor in this context.
To fix this, make your copy constructor accept const Set & instead, just like the copy member function does :
Set::Set(const Set& copied)
// ^^^^^ Added const here
{
copy(copied);
}
Edit : Mandatory disclaimer that you should not have to write your own dynamically sized array. Use std::vector instead. It will greatly simplify your type and will probably be far safer.
You can declare casting operator explicit to avoid implicit casting to bool:
explicit operator bool() const {
...
}
And then use it like this:
Set::bool(//obj_name);
I have a class to represent two-dimensional array and I want to use () operator for example,
Array arr;
arr(2,5) = 17; // I want to assign 17 as element in 2nd row and 5th column.
I tried something like that: (but is not working)
void operator(int m, int n)(int num) {
int m, n;
p[m][n] = num;
}
i have an operator = (this working):
void operator=(const Array& other) const {
for (int i = 0; i < DIM; i++) {
for (int j = 0; j < DIM; j++) {
p[i][j] = other.p[i][j];
}
}
}
Array class has T** as private member.
How can I overload () operator to access elements in array
Thank You!
You need to build something like
int& operator()(int m, int n)
which returns a reference to the array element, that you can modify through that reference at the calling site.
Don't forget to build the const overload
const int& operator()(int m, int n) const
so you can use similar syntax at a call site for element access for a const object.
Finally, for your assignment operator, you ought not make it const (have you made p mutable?), and you should return a reference to self to help compound assignment:
Array& operator=(const Array& other){
// Your existing code
return *this;
}
Reference: http://en.cppreference.com/w/cpp/language/copy_assignment
I want to overload equal to "=" operator in C++ for
class Array
{
int *p;
int len;
};
All functions/constructor etc. are defined.
My question:
Could someone give me the prototype of the operator overloaded function?
And suppose:
Array a,b;
b=a;
Which of "a" and "b" would be passed implicitly and which explicitly?
Thanks in advance.
The prototype is Array& operator=(const Array& that).
While implementing this, remember about the rule of three and make good use of the copy-and-swap idiom.
You're looking for the assignment operator = (not equal-to, which is operator== and usually serves as an equality comparison)
class Array
{
int *p;
int len;
public:
// Assignment operator, remember that there's an implicit 'this' parameter
Array& operator=(const Array& array)
{
// Do whatever you want
std::cout << "assignment called";
return *this;
}
};
int main(void) {
Array a, b;
a = b;
}
remember that since you wrote "All functions/constructor etc. are defined" you should pay attention to what you need your class to do and possibly also implement destructor as in the rule of three (and/or take a look at its variants in C++11, might be relevant since there's no other code posted).
There is probably more than one way to do it, but here is an option.
Public Functions:
Array::Array(const Array& array)
{
Allocate(0);
*this = array;
}
Array::~Array()
{
Deallocate();
}
const Array& Array::operator=(const Array& array)
{
if (this == &array)
return *this;
Deallocate();
Allocate(array.len);
for (int i=0; i<len; i++)
p[i] = array.p[i];
return *this;
}
Non-Public Functions:
void Array::Allocate(int size)
{
len = size;
if (len > 0)
p = new int[len];
}
void Array::Deallocate()
{
if (len > 0)
delete[] p;
len = 0;
}
Of course, you can always use a vector<int> instead...
I want to be able to sort a vector of a "card" class using the sort function like so:
struct Card
{
int Number;
char Suit;
};
vector<Card> hand;
std::sort (hand.begin(), hand.end());
So i overloaded the < operator for the card class so see if this would allow sort to work, but I am getting an error while comparing the "Number" variables. (Number is undefined).
bool operator < (const Card);
bool Card::operator < (const Card ob)
{
if (Number < ob.Number){
return true;
}
else
{
return false;
}
}
First, I want to make sure if this will even allow sort to work, and second, I would like some advice as to how to get Num to compare correctly
The data member is called Number, not Num.
While you're at it, change the operator to take the argument by reference:
bool Card::operator < (const Card& ob)
^ THIS
Finally, the entire if can be succinctly expressed as
return (Num < ob.Num);
Yes it will work, but you need to use Number
bool Card::operator < (const Card& ob)
{
return (Number < ob.Number) ;
}
Number is what you've used as member in your struct Card
The name of the corresponding data member is Number not Num.
The correct declaration and definition of the operator will look as
bool operator < ( const Card & ) const;
bool Card::operator < ( const Card &ob ) const
{
return Number < ob.Number;
}
you have Number member in your Card class, not Num.
refactor
struct Card
{
int Number;
char Suit;
};
to
struct Card
{
int Num;
char Suit;
};
or change function (and take argument by reference regardless if you refactor class or function body):
bool Card::operator < (const Card& ob)
^
use reference
{
return (Number < ob.Number) ; //this will replace correctly your if condition
^ ^
}
I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through
This is what I call to cause the problems.
cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
Kev *= 4.0f;
cMatrix Baz = Kev;
Kev = Kev+Baz; //HERE!
What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.
//header
class cMatrix
{
private:
float* _internal;
UInt32 _r;
UInt32 _c;
bool _zeroindexed;
//fast, assumes zero index, no safety checks
float cMatrix::_getelement(UInt32 r, UInt32 c)
{
return _internal[(r*this->_c)+c];
}
void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
{
_internal[(r*this->_c)+c] = Value;
}
public:
cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
cMatrix( cMatrix& m);
~cMatrix(void);
//operators
cMatrix& operator + (cMatrix m);
cMatrix& operator += (cMatrix m);
cMatrix& operator = (const cMatrix &m);
};
//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
cMatrix::~cMatrix(void)
{
delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m)
{
return cMatrix(*this) += m;
}
cMatrix& cMatrix::operator*(float f)
{
return cMatrix(*this) *= f;
}
cMatrix& cMatrix::operator*=(float f)
{
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] *= f;
}
return *this;
}
cMatrix& cMatrix::operator+=(cMatrix m)
{
if (_c != m._c || _r != m._r)
{
throw new cCTException("Cannot add two matrix classes of different sizes.");
}
if (!(_zeroindexed && m._zeroindexed))
{
throw new cCTException("Zero-Indexed mismatch.");
}
for (UInt32 row = 0; row < _r; row++)
{
for (UInt32 column = 0; column < _c; column++)
{
float Current = _getelement(row, column) + m._getelement(row, column);
_setelement(row, column, Current);
}
}
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix &m)
{
if (this != &m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
delete[] _internal;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
return *this;
}
Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:
cMatrix cMatrix::operator+(cMatrix const& m)
{
cMatrix matrix(*this);
matrix += m;
return matrix;
}
cMatrix cMatrix::operator*(float f)
{
cMatrix matrix(*this);
matrix *= m;
return matrix;
}
You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.
PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.
PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.
IMO the canonical form of overloading addition is this:
class X {
public:
X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};
inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}
The same goes for -, *, /, where applicable.
Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.