• 04-21-2009
scwizzo
I'm working on an arbitrary precision decimal class. I have everything working so far, but when I try to overload the = operator weird stuff happens. I can assign values to another variable of the same class, but only once. After that the values start to become messed up. There's some examples of what I mean below. The values of dub1 + dub2 does not add up to an integer of 4, but 3 dub1's do from the previous = assignment above the ret2 = dub1 + dub2. If I do only the first assignment (they're in blue) then it works correctly. The addition and subtraction both work correctly given its not assigned to something twice. All the code is there in case anyone needs a reference. The important parts are in blue.

Code:

``` //this typedef is to be used inside the class _double only typedef unsigned int *__double;   //templated class for _double //MAXSIZE is the maximum precision of the value of _double //the first element in the array is considered the integer //the numbers from position 1 to MAXSIZE are considered decimals template<int MAXSIZE> class _double {     private:         __double bigdouble;// = new int[MAXSIZE];         public:         _double(); //constructor         _double(int i, int* d, int size); //secondary constructor         ~_double(); //destructor                 void copy(_double a); //copies b to a                 //begin addition operator overloading         friend _double operator + (const _double a, const _double b)         {             _double<MAXSIZE> ret; //return value             int carry = 0;                         for(int i = MAXSIZE - 1; i >= 0; i--){                                 ret.bigdouble[i] = ( a.bigdouble[i] + b.bigdouble[i] + carry ) % 10; //find digit for current position                 carry = ( a.bigdouble[i] + b.bigdouble[i] + carry ) / 10; //find carry over digit             }                         return ret;            } //end operator+                 friend _double operator * (const _double a, const _double b)         {             _double<MAXSIZE> ret;             return ret;         }                 friend _double operator - (const _double a, const _double b)         {             _double<MAXSIZE> ret;                         for(int i = MAXSIZE - 1; i >= 0; i--){                                 if(a.bigdouble[i] >= b.bigdouble[i])                     ret.bigdouble[i] = a.bigdouble[i] - b.bigdouble[i];                 else if(a.bigdouble[i] < b.bigdouble[i]){                     int j = i-1;                     while(a.bigdouble[j] == 0){ j--; }                                         a.bigdouble[j] = a.bigdouble[j] - 1;                                         for(j=j+1; j <= i; j++){                         a.bigdouble[j] += 10;                         if(j != i) a.bigdouble[j] -= 1;                     }                                         ret.bigdouble[i] = a.bigdouble[i] - b.bigdouble[i];                 }             }             return ret;         }                 _double operator = (const _double a) const         {             _double<MAXSIZE> ret;             for(int i = 0; i < MAXSIZE; i++)                 ret.bigdouble[i] = a.bigdouble[i];             return ret;         }                 void print(); //print the value of _double }; template<int MAXSIZE> _double<MAXSIZE>::_double() {     bigdouble = new unsigned int[MAXSIZE]; //allocate required space         //set the entire array to zero     for(int i = 0; i < MAXSIZE; i++){         //if(i >= MAXSIZE) break; //safe guard just in case         bigdouble[i] = 0; //set to zero     } } //end constructor template<int MAXSIZE> _double<MAXSIZE>::_double(int i, int d[], int size) {     bigdouble = new unsigned int[MAXSIZE]; //allocate required space         bigdouble[0] = i;     //set the entire array to zero     for(int i = 1; i < MAXSIZE; i++){                 if(i-1 < size)             bigdouble[i] = d[i-1]; //set to zero         else             bigdouble[i] = 0;     } } //end constructor template<int MAXSIZE> _double<MAXSIZE>::~_double(){ delete [] bigdouble; } //delete allocated space //prints all the digits that are stored in the array template<int MAXSIZE> void _double<MAXSIZE>::print() {     cout<<bigdouble[0]<<"."<<endl;     for(int i = 1; i < MAXSIZE; i++)         cout<<bigdouble[i]; } //copies the contents of a template<int MAXSIZE> void _double<MAXSIZE>::copy(_double a) {     for(int i = MAXSIZE - 1; i >= 0; i--)         bigdouble[i] = a.bigdouble[i]; } //the main program int main() {     int decimal[] = {3,4,7};     _double<10> dub1(1,decimal,3);         int decimal2[] = {2,6,9};     _double<10> dub2(0,decimal2,3);         dub1.print(); cout<<endl<<endl;     dub2.print(); cout<<endl<<endl;         _double<10> ret = dub1;// + dub1;     _double<10> ret2 = (dub1 + ret) + ret;         ret2 = dub1 + dub2;         ret2.print();         return 0; } //The output from above int main() code 1. 347000000 0. 269000000 4. 041000000 Process returned 0 (0x0)  execution time : 0.016 s Press any key to continue.```
• 04-21-2009
anon
Operator= should modify the left-hand value and return *this, not create a local object and return that. It's not the returning that makes assignment work, the return value just lets you chain assignments.

Code:

```//this typedef is to be used inside the class _double only typedef unsigned int *__double;```
Then why not move it into the private section of the class? And identifiers beginning with double underscores are reserved for compiler writers. Identifiers beginning with any number of underscores are bad taste, IMO, as the meaning they give you is that you shouldn't use them: they are compiler-specific identifiers only to be used for implementing the standard library and other compiler-specific things.

Code:

`bigdouble = new unsigned int[MAXSIZE]; //allocate required space`
Since MAXSIZE is template parameter and therefore a compile-time constant, you could just use a normal array. (Unless you plan to use bignums that are measured in kilobytes, in which case you might conserve quite a lot of space by using a smaller data type, like char.)

Code:

```void copy(_double a); //copies b to a //copies the contents of a template<int MAXSIZE> void _double<MAXSIZE>::copy(_double a)```
Which way is it then? In any case this just duplicates the assignment operator.
• 04-21-2009
laserlight
Note that names that begin with an underscore followed by an uppercase letter, or that contain consecutive underscores, are reserved to the (compiler and standard library) implementation for any use. Names that begin with an underscore are reserved to the implementation for use as a name in the global and ::std namespaces.

Quote:

Originally Posted by scwizzo
I have everything working so far, but when I try to overload the = operator weird stuff happens.

Why is your overloaded operator= declared const? The fundamental semantics of operator= is that it modifies the current object. On the other hand, a member function named print is unlikely to modify the current object, yet it is non-const. A weird take on const correctness, methinks ;)

Another thing that you can do is to implement the assignment versions of the various operators as well. You could then implement say, operator+= as a member function, then implement operator+ as a free function using operator+=. Your assignment operators (including the copy assignment operator) should return by reference, not by value.
• 04-21-2009
scwizzo
Blah, I've been away from programming for a while and I've forgotten a bit. Thanks for the help/suggestions, I'll change my code accordingly and report back.
• 04-21-2009
scwizzo
I was able to get it to work kind of, but I run in to runtime errors that I'm thinking are coming from buffer overflows. Problem is I'm not sure how to solve it. I fixed the things you guys mentioned about the underscores, returning *this, and also looked at a dozen or more examples. If I uncomment the two lines I get errors. The weird thing about the runtime errors is it runs all the way to the end of main() and then stops. I've put cout<<"done" statements just before return 0; and it displays them. The only thing I changed in main() was the cout statement. The rest of the class is the same except for the change from _double to bdouble. Anywho, here's the code and error(s).

Code:

```        bdouble & operator = (bdouble a)         {             if(this != &a){                 //delete [] this->bigdouble;                 //bigdouble = new unsigned int[MAXSIZE];                 for(int i = 0; i < MAXSIZE; i++)                     bigdouble[i] = a.bigdouble[i];             }             return *this;         } //errors incompatible types in assignment of `unsigned int*' to `unsigned int[10]'```
• 04-21-2009
laserlight
On which line is the error identified?

By the way, instead of manually managing memory, you might want to make use of std::vector or std::tr1::array.
• 04-22-2009
anon
You don't seem to have a copy constructor. (BTW, if you did use something smarter over dynamically allocated array - even a stack array - you wouldn't need to write neither a copy constructor, assignment operator nor destructor.)

Code:

```                //delete [] this->bigdouble;                 //bigdouble = new unsigned int[MAXSIZE];```
Although this has nothing to do with the problem (that this->bigdouble may already be deleted by a copy), that code would be rather meaningless. You want to deallocate memory only to allocate the exact same amount of memory again!?
• 04-22-2009
scwizzo
Quote:

Originally Posted by anon
Although this has nothing to do with the problem (that this->bigdouble may already be deleted by a copy), that code would be rather meaningless. You want to deallocate memory only to allocate the exact same amount of memory again!?

It was originally to remove anything there, but yea it was kind of pointless and that's why I commented it out.

Laserlight, I actually started changing everything over to vectors after I posted that last night as I had the same thought. Managing everything myself became pretty difficult.

As for the line that's causing the problem, I don't know. I've put cout statements all over the class and main() and every line is printed, it only crashes when it reaches return 0;. I'll see if changing things to vectors makes things better in the end (and hopefully fixes the run time errors).
• 04-22-2009
anon
Quote:

that this->bigdouble may already be deleted by a copy
Did you understand that. If you don't define a copy constructor but use it, the copy will point to the same dynamically allocated array. If either of them goes out of scope, the other is left with a dangling pointer since the destructor deletes the shared array. When the second one goes out of scope, its destructor attempts to delete the shared array again. All kinds of funny things (can) come out of this.

This won't be a problem if you switch to std::vector, since that manages resource allocation, deallocation and copying for you.