I am writing a bignum implementation and in it I overloaded operators + and =. Here is my code that does it:
BigNum& operator+(const BigNum& b ) {
BigNum sum;
int carry=0;
for (int i=0; i<N;i++){
sum.dig[i]=(dig[i]+b.dig[i]+carry)%10;
carry=(dig[i]+b.dig[i]+carry)/10;
}
return sum;
}
BigNum& operator=(const BigNum& rhs ) {
for (int i=0; i<N; i++){
dig[i]=rhs.dig[i];
}
return *this;
}
They both seem to be working well on their own (I can assign a bignum to a bignum correctly and add two bignums correctly) but when I try to combine them I get answers that seem to be random. So if a and b are bignums, it's okay if I say
BigNum c=b;
and
cout<<a+b;
but
a=a+b;
gives an unexpected result.
You are returning a reference to a local variable sum from your + operator. You can't meaningfully return references or pointers to local variables. Because of this error the behavior of your code is undefined, which the reason for your "unexpected results".
Since you are implementing a regular binary +, you have to return the result by value
BigNum operator +(const BigNum& b) const {
BigNum sum;
...
return sum;
}
As an additional note, binary + make more sense as a standalone (possibly friend) function, not as a class member. If you want to keep it as a class member, at least declare it const (see above).
A separate question is what dig is, what N is and whether your class violates the Rule Of Three. But it is impossible to say from what you posted.
This may not answer your question but I believe it will improve your code and as such, it's a "suggestion".
It would be wise to implement the + operator to create a temporary that invokes the += operator.
For example:
BigNum& operator += (const BigNum &other) {
int carry = 0;
for (int i = 0; i < digits_length; ++i) {
int temp = digit[i];
digit[i] = (digit[i] + other.digit[i] + carry) % 10;
carry = (temp + other.digit[i] + carry) / 10;
}
return *this;
}
BigNum operator + (const BigNum& other) const {
return BigNum(*this) += other;
}
Related
Consider a simple vector class realization:
#include <algorithm>
class Vector {
public:
Vector(int _elementsCount)
: elementsCount(_elementsCount)
, elements(new float[_elementsCount])
{}
~Vector() {
delete[] elements;
}
Vector(const Vector& rhs) {
elementsCount = rhs.size();
elements = new float[elementsCount];
for (int i = 0; i < elementsCount; ++i)
(*this)[i] = rhs[i];
}
float& operator [](int i) {
return elements[i];
}
float operator [](int i) const {
return const_cast<Vector&>(*this)[i];
}
int size() const {
return elementsCount;
}
/*// Dot product
float operator *(const Vector& v) {
float res = 0;
for (int i = 0; i < size(); ++i)
res += (*this)[i] * v[i];
return res;
}*/
private:
int elementsCount;
float* elements;
};
// Multiplication by a scalar
Vector operator *(const Vector& v, float k) {
Vector res(v.size());
for (int i = 0; i < v.size(); ++i)
res[i] = v[i] * k;
return res;
}
// Dot product
float operator *(const Vector& v1, const Vector& v2) {
float res = 0;
for (int i = 0; i < std::min(v1.size(), v2.size()); ++i)
res += v1[i] * v2[i];
return res;
}
void main()
{
Vector v(2);
v * 3; // ambiguous
}
This code compiles. But if we uncomment * operator realization in the class and comment its global realization (dot product function), then there will be an error "'Vector::operator *': 2 overloads have similar conversions", because there is an ambiguity: whether to call the multiplication by a scalar or to interpret 3 as an argument to a parametrized constructor and to call the dot product. This makes sense. But I don't get what's the difference of declaring the * operator as a member function or as a global function. I thought they should be the same in the example like above, but it's not the case.
Added. The thing I most interested in is not how to avoid the ambiguity, but why there is an ambiguity in one case (when * is declared as a member) and there is no one in the other (when * is declared as a global function).
You need to make your constructor explicit:
explicit Vector(int _elementsCount) { ... }
The reason for the ambiguity is that the compiler can't decide whether it should implicitly convert a int value to a Vector and invoke Vector::operator*, or implicitly convert a int value to a float and use operator*(const Vector&, float).
By using explicit, such conversions are forbidden, and you must use Vector(3) if you want "3" to be a Vector.
As a side-note, you should make the operator const, since it does not modify the object. Making it const will also allow it to be used with a const Vector:
float operator *(const Vector& v) const { ... }
Beware that will still conflict with your other overload:
float operator *(const Vector& v1, const Vector& v2)
There is no reason to have both. Choose either the member function or the global function and remove the other.
I have created a Vector class that holds 3 parameters and overloaded the -= operator
template <class T>
class Static3Vector
{
public:
Static3Vector() : m_coords{ 0, 0, 0 } {}
Static3Vector(T x, T y, T z) : m_coords{ x, y, z } {}
T operator [] (const size_t& i) { return m_coords[i]; }
T operator [] (const size_t& i) const { return m_coords[i]; }
Static3Vector operator -= (const Static3Vector& rhs)
{
for (int i = 0; i < sizeof(m_coords) / sizeof(m_coords[0]); i++)
this[i] -= rhs[i];
return *this;
}
private:
T m_coords[3];
};
but when I try using this operator
Static3Vector<int> vec1(1,2,3);
Static3Vector<int> vec2(1,2,3);
vec1 -= vec2;
I get the error I typed out in the title.
this is a pointer and this[i] is not doing what you expect. It takes this and performs pointer arithmetic. The only value of i that is not UB is then 0 and type of this expression is Static3Vector<T>
It is pretty much equivalent to this:
Static3Vector<int> vec1(1,2,3);
Static3Vector<int>* ptr = &vec1;
ptr[0]; //ok, equivalent to *ptr
ptr[1]; //compiles, but invokes UB
You can solve it in a couple of ways:
(*this)[i] -= rhs[i]; //dereference first
this->operator[](i) -= rhs[i]; //call operator explicitly
m_coords[i] -= rhs[i]; //don't use overloaded operator, use data directly
One more thing: First two will not work with your current implementation, because your operator[] returns a copy of the value it stores. It's more typical for operator[] to return a reference to stored object:
T& operator [] (const size_t& i) { return m_coords[i]; }
const T& operator [] (const size_t& i) const { return m_coords[i]; }
See also What are the basic rules and idioms for operator overloading?
Take a look at your indexing-operators:
T operator [] (const size_t& i) { return m_coords[i]; }
T operator [] (const size_t& i) const { return m_coords[i]; }
The only difference between them is that one is called for constant objects, begging the question why you duplicated them at all.
That is easily answered though:
Both should return references, the latter const-qualified, to avoid copies and allow modification for the first one.
Fix that as a first step to resolving your error.
As a second step, recognize that this was introduced before references existed, and is thus a pointer to the instance, not a reference, thus this[n] is pointer-arithmetic, not calling your custom indexing-operator. Thankfully that results in a different type and thus failed overload-resolution.
there is incorrect use of the subscript operator. In the operator definitions as for example in this
Static3Vector operator -= (const Static3Vector& rhs)
{
for (size_t i = 0; i < sizeof(m_coords) / sizeof(m_coords[0]); i++)
this[i] -= rhs[i];
return *this;
}
in this statement
this[i] -= rhs[i];
there is used the b built-in subscript operator for an object of the pointer type Static3Vector *.
You need to write
( * this )[i] -= rhs[i];
or
this->operator[]( i ) -= rhs[i];
Also the return type shall be a referenced type like
T & operator [] (const size_t& i) { return m_coords[i]; }
const T & operator [] (const size_t& i) const { return m_coords[i]; }
and
Static3Vector & operator -= (const Static3Vector& rhs)
{
for (size_t i = 0; i < sizeof(m_coords) / sizeof(m_coords[0]); i++)
( *this )[i] -= rhs[i];
return *this;
}
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.
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.
Ok, I am working through a book and trying to learn C++ operator overloading. I created a BigInt class that takes a single int (initially set to 0) for the constructor. I overloaded the += method and it works just fine in the following code:
BigInt x = BigInt(2);
x += x;
x.print( cout );
The code will output 4. So, then I was working on overloading the global operator + using the following code:
BigInt operator+(const BigInt lhs, const BigInt rhs)
{
BigInt returnValue(lhs);
returnValue += rhs;
return returnValue;
}
This also works fine for the following code:
BigInt x = BigInt(1);
BigInt y = BigInt(5);
BigInt z = x + y;
z.print();
This prints out 6. However, when I try to execute the following code, it just doesn't work. The book doesn't explain very well and implies that it should simply work.
BigInt x = BigInt(1);
BigInt z = x + 5;
z.print();
This prints out 1. I'm not sure why z is 1 when it should be 6. I googled online and on stackoverflow but I couldn't find anyone else that was having a problem exactly like this. some were close, but the answers just didn't fit. Any help is much appreciated!
most likely problem is in += operator. Post code for it.
You need an overload for adding an int to BigInt; the constant 5 in your example is of type int, not BigInt. Something like this should work:
BigInt operator+(const BigInt lhs, const int rhs)
{
BigInt returnValue(rhs);
returnValue += lhs;
return returnValue;
}
You might want one for operator+(const int lhs, const BigInt rhs) too.
The following super-simplified code (the minimum I can add to include all your code and make it into a valid stand-alone executable program):
#include <iostream>
class BigInt
{
public:
BigInt(int i): _i(i) {}
void print() { std::cout << "BigInt(" << _i << ")\n"; }
void operator +=(const BigInt rhs) { _i += rhs._i; }
private:
int _i;
};
BigInt operator+(const BigInt lhs, const BigInt rhs)
{
BigInt returnValue(lhs);
returnValue += rhs;
return returnValue;
}
int main() {
BigInt x = BigInt(1);
BigInt y = BigInt(5);
BigInt z = x + y;
z.print();
BigInt ax = BigInt(1);
BigInt az = ax + 5;
az.print();
return 0;
}
emits, as predictable:
BigInt(6)
BigInt(6)
Please make the minimum possible alterations to this working code to reproduce the bug you observe -- that will of course show where your bug exactly lies.
The code you've posted looks fine and should work. Problems you're seeing are almost certainly due to the copy constructor or assignment operator of your BigInt class.