• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 264
  • Last Modified:

question about deconstructors

I've made a multi-dimensional array class which includes a deconstructor which properly frees up used space.  The problem is that in a member function which makes a new array object the deconstructor is automatically called at the end of the function and deletes all the objects data.  My question is, is there any way to stop the deconstructor from being called in my member function or is there some way to keep that data from being deleted by the deconstructor?  Thanks
0
kainhart
Asked:
kainhart
  • 14
  • 14
  • 8
1 Solution
 
sumant032199Commented:
One thing is you can allocate memory fisrt using  new keyword and use pointers for that which won't destroy objects I think.

Another thing is you can build static objects who's lifetime is complete program.

Thirs thing global objects.
0
 
sumant032199Commented:
sorry, spelling mistake.
Third thing global objects.
0
 
kainhartAuthor Commented:
Using Global variables or Global variables wont work for this I've tried.  The oject needs to be created inside the member function and needs to continue to exist after the function ends.  Thanks for your input though.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
nietodCommented:
>>  The problem is that in a member function
>> which makes a new array object the
>> deconstructor is automatically called at
>> the end of the function and deletes all the
>> objects data.
If the function is creating a local object then this IS what will happen there is no way around it (and that is a good thing).  for example if you do

yourclass SomeFunction()
{
   yourclass x;
   return x;
}

A the destructor will be called on x.

However that is the right thing to have happen, since x will be destroyed, x is stored with in the function and must be destroyed whent he function ends.  The valeu returned from the function is not "x"  it is a new value.  it is a value created as a copy of x.  This copy is what is returned, and it won't have its destructor called at this time.

contines
0
 
nietodCommented:
This design was created so classes work properly,  But your class probably isn't working right, that is whay you are concerend with this destructor call.  But the problem isn't with the destructor call, most likely it is with other parts of the class.  For example, if your class stores a pointer--and I suspect it does, if you haven't written a copy constructor for the class, you will have a problem in the code I showed above.   You need to write a copy constructor so that the local value (x in the code above)  can be safely copied to the caller (so x can be copied to the value to be returned).  If you don't write a copy constructor, the C compiler will try to write one for you.  Unfortuantely, it doesn't usually work well for classes that contain pointers.

Let me know if you have any questions.
0
 
kainhartAuthor Commented:
I understand how the destructor works, I just needed to know if there was a way around it.  if not, I guess I'll have to make a condition in my descrutor that only uses delete depending on if it's an object created by a client of the class or inside a class member.  Is there any other way around this?
0
 
kainhartAuthor Commented:
I know about the deep and shallow coppies also, and my class is working great except for the fact that I need the data created, my code is below take a look.


//************************************************************************************************
//                                                                  mdarray.h
//************************************************************************************************
//
// Project: Program #1
// by: Jeff Pierson
// for: CIS 350 (Professor Steiner)
//
// mdArray is multi-dimensional array class that handles up to three dimensions.  
// This class has been designed only for use with floating point numbers.
//************************************************************************************************
//************************************************************************************************


class mdArray
{
public:
      mdArray(int, int);
      mdArray(int, int, int, int);
      mdArray(int, int, int, int, int, int);
      ~mdArray();
      bool  checkRange(int, int, int);
      bool  addItem(int, int, int, float);
      float getItem(int, int, int);
      void  setValuesAs(float);
      void  initWith(mdArray & newArray);
      void  changeSize(int, int);
      void  changeSize(int, int, int, int);
      void  changeSize(int, int, int, int, int, int);
      int   selectRange(int);
      long  sizeOf();
      float * getBaseAddress();

private:
      int dimensions;
      float * baseAddress;

      struct dimensionAtrib
      {
            long size;      // Initially set to one so that when multiplied it has no effect.
            int uprBnd;
            int lowBnd;
      };

      dimensionAtrib Dim1;
      dimensionAtrib Dim2;
      dimensionAtrib Dim3;
};
//************************************************************************************************
//************************************************************************************************



//************************************************************************************************
//                                                                  mdarray.cpp
//************************************************************************************************

#include "mdarray.h"

//************************************************************************************************
mdArray::mdArray(int lB1, int uB1)
// pupose:                  Set up a one dimensional mdArray object.
// pre-condition:      uB1 >= lB1, uB2 >= lB2, and uB3 >= lB3.
// post-condition:      A one dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf                  
{
      this->dimensions = 1;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = 0;
      this->Dim2.uprBnd = 0;
      this->Dim3.lowBnd = 0;
      this->Dim3.uprBnd = 0;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = 0;
      this->Dim3.size = 0;
      
      this->baseAddress = new float[sizeOf()];
}


//************************************************************************************************
mdArray::mdArray(int lB1, int uB1, int lB2, int uB2)
// pupose:                  Set up a two dimensional mdArray object.
// pre-condition:      uB1 >= lB1, and uB2 >= lB2.
// post-condition:      A two dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf      
{
      this->dimensions = 2;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = lB2;
      this->Dim2.uprBnd = uB2;
      this->Dim3.lowBnd = 0;
      this->Dim3.uprBnd = 0;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = uB2 - lB2 + 1;
      this->Dim3.size = 0;
      
      this->baseAddress = new float[sizeOf()];
}


//************************************************************************************************
mdArray::mdArray(int lB1, int uB1, int lB2, int uB2, int lB3, int uB3)
// pupose:                  Set up a Three dimensional mdArray object.
// pre-condition:      uB1 >= lB1, uB2 >= lB2, and uB3 >= lB3.
// post-condition:      A three dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf      
{// state that lowerBound must be less than upperbound.
      
      // calculate the sizes for the upper and lower Bounds

      this->dimensions = 3;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = lB2;
      this->Dim2.uprBnd = uB2;
      this->Dim3.lowBnd = lB3;
      this->Dim3.uprBnd = uB3;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = uB2 - lB2 + 1;
      this->Dim3.size = uB3 - lB3 + 1;

      this->baseAddress = new float[sizeOf()];
}


//************************************************************************************************
mdArray::~mdArray()
// pupose:                  To deconstruct an mdArray object and free up it's used memory.
// pre-condition:      
// post-condition:      the memory allocated by the declairation of baseAdress is freed up.
// called by:            ?????.
// calls:                  none      
{
      //delete [] this->baseAddress;
}


//************************************************************************************************
bool mdArray::checkRange(int subscript1, int subscript2, int subscript3) // T in range, F out of range
// pupose:                  Check if a give set of subscripts is in the bounds of an array.
// pre-condition:      
// post-condition:      Returns True if the give subscripts are in range and
//                              False if they are out of range.
// called by:            Client of mdArray class, getItem, and addItem.
// calls:                  none
{
      int lowerBound = this->Dim1.lowBnd;
      int upperBound = this->Dim1.uprBnd;
      
      if((subscript1 >= lowerBound) && (subscript1 <= upperBound))
      {
            lowerBound = this->Dim2.lowBnd;
            upperBound = this->Dim2.uprBnd;

            if((subscript2 >= lowerBound) && (subscript2 <= upperBound))
            {
                  lowerBound = this->Dim3.lowBnd;
                  upperBound = this->Dim3.uprBnd;

                  if((subscript3 >= lowerBound) && (subscript3 <= upperBound))
                        return true;
                  else
                        return false;
            }
            else
                  return false;
      }
      else
            return false;
}


//************************************************************************************************
bool mdArray::addItem(int subSrp1, int subSrp2, int subSrp3, float item)
// pupose:                  Store a floating point value at a the given
//                              referenced location.
// pre-condition:      The given subscripts should be in range, otherwise
//                              the values will not be added.
// post-condition:      The floating point value is stored at the location
//                              referenced by the supplied subscripts.
// called by:            Client of mdArray class, initWith, setValuesAs.
// calls:                  checkRange
{
      float * ptr;

      int rowSize = this->Dim1.size;
      int tableSize = rowSize * this->Dim2.size;

      if(checkRange(subSrp1, subSrp2, subSrp3))
      {
            if(this->dimensions == 1)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd);
                  *ptr = item;
            }
            if(this->dimensions == 2)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd)
                          + (subSrp2 - this->Dim2.lowBnd) * rowSize;
                  *ptr = item;
            }
            if(this->dimensions == 3)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd)
                          + (subSrp2 - this->Dim2.lowBnd) * rowSize
                          + (subSrp3 - this->Dim3.lowBnd) * tableSize;
                  *ptr = item;
            }

            return true;
      }
      else
            return false;

}


//************************************************************************************************
float mdArray::getItem(int subSrp1, int subSrp2, int subSrp3)
// pupose:                  Get the floating point value stored at a
//                              referenced location.
// pre-condition:      The given subscripts should be in range, otherwise
//                              the values will not be returned.
// post-condition:      The floating point value in the location
//                              referenced by the supplied subscripts is returned.
// called by:            Client of mdArray class, initWith.
// calls:                  checkRange      
{
      float item;
      float * ptr;
      int rowSize = this->Dim1.size;
      int tableSize = rowSize * this->Dim2.size; // I'll have to check this.

      if(checkRange(subSrp1, subSrp2, subSrp3))
      {

            if(this->dimensions == 1)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd);
                  item = *ptr;
            }
            if(this->dimensions == 2)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd)
                          + (subSrp2 - this->Dim2.lowBnd) * rowSize;
                  item = *ptr;
            }
            if(this->dimensions == 3)
            {
                  ptr = baseAddress + (subSrp1 - this->Dim1.lowBnd)
                          + (subSrp2 - this->Dim2.lowBnd) * rowSize
                          + (subSrp3 - this->Dim3.lowBnd) * tableSize;
                  item = *ptr;
            }
      }
      // some assertion


      return item;
}


//************************************************************************************************
void mdArray::setValuesAs(float initValue)  // Set all floats to this value.
// pupose:                  Set all the elements to specified value.
// pre-condition:      initValue must be a valid floating point value.
// post-condition:      Each element is initialized to the value of
//                              initvalue.
// called by:            Client of mdArray class.
// calls:                  addItem
{
      int index1, index2, index3;

      index3 = Dim3.lowBnd;
      while((index3 <= Dim3.uprBnd))
      {
            index2 = Dim2.lowBnd;
            while((index2 <= Dim2.uprBnd))
            {
                  index1 = Dim1.lowBnd;
                  while((index1 <= Dim1.uprBnd))
                  {
                        addItem(index1, index2, index3, initValue);
                        index1++;
                  }
                  index2++;
            }
            index3++;
      }
}


//************************************************************************************************
void mdArray::initWith(mdArray & newArray)
// pupose:                  Initialize an mdArray object with the
//                              values in an another mdArray object.
// pre-condition:      
// post-condition:      Elements of the calling object which
//                              match subscripts contained in the
//                              newArray object, are set to the values
//                              found in newArray.
// called by:            Client of mdArray class, changeSize.
// calls:                  addItem, getItem
{
      int index1, index2, index3;
      int largestLowBnd1, smallestUpBnd1;
      int largestLowBnd2, smallestUpBnd2;
      int largestLowBnd3, smallestUpBnd3;

      // find the common bounds between the two arrays for first dimension
      if(this->Dim1.lowBnd >= newArray.Dim1.lowBnd)
            largestLowBnd1 = this->Dim1.lowBnd;
      else
            largestLowBnd1 = newArray.Dim1.lowBnd;
      if(this->Dim1.uprBnd <= newArray.Dim1.uprBnd)
            smallestUpBnd1 = this->Dim1.uprBnd;
      else
            smallestUpBnd1 = newArray.Dim1.uprBnd;


      // find the common bounds between the two arrays for second dimension
      if(this->Dim2.lowBnd >= newArray.Dim2.lowBnd)
            largestLowBnd2 = this->Dim2.lowBnd;
      else
            largestLowBnd2 = newArray.Dim2.lowBnd;
      if(this->Dim2.uprBnd <= newArray.Dim2.uprBnd)
            smallestUpBnd2 = this->Dim2.uprBnd;
      else
            smallestUpBnd2 = newArray.Dim2.uprBnd;


      // find the common bounds between the two arrays for third dimension
      if(this->Dim3.lowBnd >= newArray.Dim3.lowBnd)
            largestLowBnd3 = this->Dim3.lowBnd;
      else
            largestLowBnd3 = newArray.Dim3.lowBnd;
      if(this->Dim3.uprBnd <= newArray.Dim3.uprBnd)
            smallestUpBnd3 = this->Dim3.uprBnd;
      else
            smallestUpBnd3 = newArray.Dim3.uprBnd;


      // copy values from newArray to the array which is calling this function
      index3 = largestLowBnd3;
      while((index3 <= smallestUpBnd3))
      {
            index2 = largestLowBnd2;
            while((index2 <= smallestUpBnd2))
            {
                  index1 = largestLowBnd1;
                  while((index1 <= smallestUpBnd1))
                  {
                        this->addItem(index1, index2, index3, newArray.getItem(index1, index2, index3));
                        index1++;
                  }
                  index2++;
            }
            index3++;
      }

}


//************************************************************************************************
void mdArray::changeSize(int lB1, int uB1)
// pupose:                  changes the size of an mdArray object to a one
//                              dimensional array with the specified bounds.
// pre-condition:      uB1 >= lB1.
// post-condition:      The calling object will be set to one
//                              dimension and bounds specified.
// called by:            Client of mdArray class.
// calls:                  initWith
{
      mdArray newArray(lB1, uB1);

      newArray.initWith(*this);

      this->baseAddress = newArray.baseAddress;

      this->dimensions = newArray.dimensions;

      this->Dim1.lowBnd = newArray.Dim1.lowBnd;
      this->Dim1.uprBnd = newArray.Dim1.uprBnd;
      this->Dim2.lowBnd = newArray.Dim2.lowBnd;
      this->Dim2.uprBnd = newArray.Dim2.uprBnd;
      this->Dim3.lowBnd = newArray.Dim3.lowBnd;
      this->Dim3.uprBnd = newArray.Dim3.uprBnd;

      this->Dim1.size = newArray.Dim1.size;
      this->Dim2.size = newArray.Dim2.size;
      this->Dim3.size = newArray.Dim3.size;
}


//************************************************************************************************
void mdArray::changeSize(int lB1, int uB1, int lB2, int uB2)
// pupose:                  changes the size of an mdArray object to a two
//                              dimensional array with the specified bounds.
// pre-condition:      uB1 >= lB1, and uB2 >= lB2.
// post-condition:      The calling object will be set to two
//                              dimensions and bounds specified.
// called by:            Client of mdArray class.
// calls:                  initWith      
{
      mdArray newArray(lB1, uB1, lB2, uB2);

      newArray.initWith(*this);

      this->baseAddress = newArray.baseAddress;

      this->dimensions = newArray.dimensions;

      this->Dim1.lowBnd = newArray.Dim1.lowBnd;
      this->Dim1.uprBnd = newArray.Dim1.uprBnd;
      this->Dim2.lowBnd = newArray.Dim2.lowBnd;
      this->Dim2.uprBnd = newArray.Dim2.uprBnd;
      this->Dim3.lowBnd = newArray.Dim3.lowBnd;
      this->Dim3.uprBnd = newArray.Dim3.uprBnd;

      this->Dim1.size = newArray.Dim1.size;
      this->Dim2.size = newArray.Dim2.size;
      this->Dim3.size = newArray.Dim3.size;
}


//************************************************************************************************
void mdArray::changeSize(int lB1, int uB1, int lB2, int uB2, int lB3, int uB3)
// pupose:                  changes the size of an mdArray object to a three
//                              dimensional array with the specified bounds.
// pre-condition:      uB1 >= lB1, uB2 >= lB2, and uB3 >= lB3.
// post-condition:      The calling object will be set to three
//                              dimensions and bounds specified.
// called by:            Client of mdArray class.
// calls:                  initWith      
{
      mdArray newArray(lB1, uB1, lB2, uB2, lB3, uB3);

      newArray.initWith(*this);

      this->baseAddress = newArray.baseAddress;

      this->dimensions = newArray.dimensions;

      this->Dim1.lowBnd = newArray.Dim1.lowBnd;
      this->Dim1.uprBnd = newArray.Dim1.uprBnd;
      this->Dim2.lowBnd = newArray.Dim2.lowBnd;
      this->Dim2.uprBnd = newArray.Dim2.uprBnd;
      this->Dim3.lowBnd = newArray.Dim3.lowBnd;
      this->Dim3.uprBnd = newArray.Dim3.uprBnd;

      this->Dim1.size = newArray.Dim1.size;
      this->Dim2.size = newArray.Dim2.size;
      this->Dim3.size = newArray.Dim3.size;
}


//************************************************************************************************
int mdArray::selectRange(int dimension)
// pupose:                  Select range of a specified dimension.
// pre-condition:      dimension must have the value 1, 2, or 3.
// post-condition:      The size of the dimension specified by
//                              dimension is returned.
// called by:            Client of mdArray class.
// calls:                  none
{
      switch(dimension)
      {
      case 1:      return Dim1.size;
                  break;
      case 2:      return Dim2.size;
                  break;
      case 3:      return Dim3.size;
                  break;
      /*default: // assert something here like not a dimension */
      }
}


//************************************************************************************************
long mdArray::sizeOf()
// pupose:                  Return the number of elements in array.
// pre-condition:      
// post-condition:      The size of the array in number of elements
//                              is returned.
// called by:            Client of mdArray class, mdArray.
// calls:                  none
{// size is in number of items.

      if(this->dimensions == 1)
            return Dim1.size;
      if(this->dimensions == 2)
            return Dim1.size * Dim2.size;
      if(this->dimensions == 3)
            return Dim1.size * Dim2.size * Dim3.size;
}


//************************************************************************************************
float * mdArray::getBaseAddress()
// pupose:                  Get address to the first element of mdArray object.
// pre-condition:      
// post-condition:      Returns the address of the first floating point element of
//                              the calling mdArray object.
// called by:            Client of mdArray class.
// calls:                  none      
{
      return baseAddress;
}
0
 
kainhartAuthor Commented:
The three overloaded changeSize functions are the member functions I'm questioning about.  Thanks
0
 
nietodCommented:
Where is the problem?  Can you point it out?
0
 
nietodCommented:
that was fast...
0
 
nietodCommented:
Inside the first changesize(), the line

this->baseAddress = newArray.baseAddress;

is a problem.  It leaves two array objects that both have "baseAddress" pointers that point to the same bock of memory.  That is an error.  No matter what design you have one object will be destroyed before the other.  When the first one is destroyed (newArray, in the current design) the second one is left holding a pointer to deleted memory.  the solution is not to prevent the destructor from being called--that is not allowed, as it would introduce potential for 100s more problems.   The solution is to hever left the two objects share pointers.  You ned to allocate a new block of memory for the "this" object using new.

continues.
0
 
nietodCommented:
void mdArray::changeSize(int lB1, int uB1)
              // pupose: changes the size of an mdArray object to a one
              // dimensional array with the specified bounds.
              // pre-condition: uB1 >= lB1.
              // post-condition: The calling object will be set to one
              // dimension and bounds specified.
              // called by: Client of mdArray class.
              // calls: initWith
{
// If you had a working operator =, you could just use
// *this = newArray; and you would be done.  since you
// don't, newArray isn't of any value at all.
//              mdArray newArray(lB1, uB1);  // gone


float *NewArray = new float[XXXXX];  // You need to figure
  // out XXXX.  I'm not sure of the details.
 
// then use a loop to copy values from the old array
// (baseAddress) to the new array (NewArray);

// then delete the old array.
   delete [] baseAddress;

// Then use the new array;
   baseAddress = NewArray;

// Then set the bouds and  dimensions as appropriate.
              this->Dim1.lowBnd = XXXX;
              this->Dim1.uprBnd = XXXX;
              this->Dim2.lowBnd = XXXXX;
                  *   *   *
}
0
 
nietodCommented:
A good idea would be to make a single initialization procedure.  This would be a private procedure that is used by the 3 constructors and by the chagesize procedure.  it would take an integer that indicates the new number of dimesnsions, and the bounds for 3 dimesions (it might ignore some of these if the new number of dimensions is only 1 or 2).  The procedure would try to allocate space for the new number of dimesions and bounds and would copy the old data stored to the new array alocated, then it woudl delete the old array.  in other words it would everything the current ChangeSize() needs to do, except it works in 1,2, or 3 dimesions.  By doing this you make changeSize() trivial, it just calls this new function.  However the other advantage is that all 3 cnstructors also become trivial.  They just set of the array so that the baseAddress pointer  is NULL, and set the bounss and dimmensiosn to 0, then they call this initialzation procedure and it does all the work.
0
 
kainhartAuthor Commented:
Thanks that should work.
0
 
sumant032199Commented:
What is wrong in my answer?
I understood that preventing compiler from deleting object is not a solution but my fist answer describes three tricks which really work. static object is the best solution hare.



#include <iostream.h>
#include <conio.h>

class  Anything
{
     private:
      int i;
     public:
      Anything(int p){ i=p;}
      ~Anything()
      {
           cout << "\nThis is destructor == " << i;
      }
};
void some(void);
void main(void)
{
     clrscr();
     some();
     cout << "\nMain Declaration ";
}
void some(void)
{
     static Anything A(1);
     Anything *a;
     a=new Anything(2);
     cout << "\nDeclaration ";
}
0
 
kainhartAuthor Commented:
Nothing is wrong with your answer it's just that it wasn't indepth enough for somebody of my level of experience.  Thanks for trying to help me though.
0
 
sumant032199Commented:
It's OK.

What if we declare a destructor in follwing way?
class A
{
     A(){}
     ~A()
     {
          delete this;

     }
};

0
 
nietodCommented:
>> What if we declare a destructor
>> in follwing way?
Try it and see.    

Post a comment here when you program finishes.  :-)

0
 
sumant032199Commented:
Yes, I have done it already in many ways. It stops execution at "delete this" It can not escape from that line. I tried in dubging mode also.
0
 
sumant032199Commented:
Please nietod, have a look at my very first rejected answer and please explain me why that difference is there
1> 'new'ed object does not get destroyed through destructor, even when program ends. My sample program proves that. Static does.
0
 
nietodCommented:
>>  It stops execution at "delete this
No it doesn't.  It recusrses.  Delete does two things.  It calls the destructor, then it frees the memory.  You destructor calls delete.  So delete calls the denstructor, that call delete, that calls the destructor, that calls delete....

>> One thing is you can allocate memory
>> fisrt using  new keyword and use pointers
>> for that which won't destroy objects I think.
That is a very very general statement.  So general that it is almost always useless.   In this case how does it help kainhart?  He is already alocating memory.  To make his code work with this approach he would have to allocate array objects in his functions using new and then never delete them.  If he did that the bug would dissappear and he woudl have a steady memory leak instead. That is not very good.  

>> Another thing is you can build static objects
>> who's lifetime is complete program.
Again, completely general.  How does he apply this?  Well in his canse he would need to create the local array objects as statics.  His bug would again dissappear, the first time the function would be called.  It would crash the second time.

>> Thirs thing global objects.
Same as above.

>> 1> 'new'ed object does not get
>> destroyed through destructor,
>> even when program ends. My
>> sample program proves that. Static
>> does.
Are you proposing a solution to allocate with new and to never call delete?  That is simply a bad programming practice.  That is unjustifiable.

The root of the problem is that you let kainhart's errors suck you in.  He isn't an expert, he is beginner and is likely to make attrocious mistakes.  Look at the question

>> The problem is that in a member function
>> which makes a new array object the
>> deconstructor is automatically called at the
>> end of the function and deletes all the objects
>> data.

As an expert in C++ you should realize that his perceived problem, the fact that the destructor is getting called is neither avoidable (it is a requirement of C++) nor a problem (it is necessary, the fact that the destructor is called at the end of an object's life is a fundamental feature of the language that cannot be changed and that is used to support many many other features of the language an of programs written in it.)  So his problem isn't the destructor call.  It should be called whenever an object is being "removed" from existance.  You cannot justify an argument that is should not.  Instead the problem is that this destruction is exposing existing problems in the program.  But the client doesn't know this, but you should.  My first thought was that there are two objects that have pointers to the same data.  When 1 is detroyed, the other is left dangling.  This was the problem, however it was not due to a misisng copy constructor, which was my first thought (because it sounded like this occurs when he "returns" an object from a procedure, which was not the case at all.)
0
 
sumant032199Commented:
>> Post a comment here when you program finishes.  :-)

Nice comment nietod.
Your explanation is right on target...wonderful.
When I read kainhart's question, without bothering anything I gave him
the ways(so called) so that program won't delete objects. I was knowing
that preventing the deletion is not a solution, but somehow I ignored that and answered the question.

The explanation about destructor -- delete relation was a great help for me to understand how destructor works.

>> Are you proposing a solution to allocate with new and to never call delete?  That is simply a bad programming practice.  That is unjustifiable.
100% Agreed.
0
 
kainhartAuthor Commented:
Here is the part of the program I changed.  It's works fine this way.

//************************************************************************************************
//                                                                  mdarray.h
//************************************************************************************************
//
// Project: Program #1
// by: Jeff Pierson
// for: CIS 350 (Professor Steiner)
//
// mdArray is multi-dimensional array class that handles up to three dimensions.  
// This class has been designed only for use with floating point numbers.
//************************************************************************************************
//
// mdArray class usage:
//
//      *      To declare a mdArray object in client program use the following blaghblagh
//                  mdArray arrayToCreate(lowerbound1, upperbound1, lowerbound2, upperbound2)
//            the lowerbound1 and upperbound1 variables will give the values for the
//            upper and lower bounds of the first dimension.
//            the lowerbound2 and upperbound2 variables will give the values for the
//            upper and lower bounds of the second dimension.
//            To make a three dimensional array an additional two bounds would be passed
//            as perameters in the constructor.
//
//      *      The convension that members functions of this class use to reference a location
//            is a three integer subscript
//                  Ex. addItem(firstSub, secondSub, thirdSub)
//                  where firstSub references an element in the first dimension
//                          secondSub references an element in the second dimension ect...
//      
//            
//
//************************************************************************************************


class mdArray
{
public:
      mdArray(int, int);
      mdArray(int, int, int, int);
      mdArray(int, int, int, int, int, int);
      ~mdArray();
      bool  checkRange(int, int, int);
      bool  addItem(int, int, int, float);
      float getItem(int, int, int);
      void  setValuesAs(float);
      void  initWith(mdArray & newArray);
      void  changeSize(int, int);
      void  changeSize(int, int, int, int);
      void  changeSize(int, int, int, int, int, int);
      int   selectRange(int);
      long  sizeOf();
      float * getBaseAddress();

private:
      int dimensions;
      bool deconstructable;
      float * baseAddress;

      struct dimensionAtrib
      {
            long size;      // Initially set to one so that when multiplied it has no effect.
            int uprBnd;
            int lowBnd;
      };

      dimensionAtrib Dim1;
      dimensionAtrib Dim2;
      dimensionAtrib Dim3;
};
//************************************************************************************************
//************************************************************************************************




//************************************************************************************************
//                                                                  mdarray.cpp
//************************************************************************************************

#include "mdarray.h"

//************************************************************************************************
mdArray::mdArray(int lB1, int uB1)
// pupose:                  Set up a one dimensional mdArray object.
// pre-condition:      uB1 >= lB1, uB2 >= lB2, and uB3 >= lB3.
// post-condition:      A one dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf                  
{
      this->dimensions = 1;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = 0;
      this->Dim2.uprBnd = 0;
      this->Dim3.lowBnd = 0;
      this->Dim3.uprBnd = 0;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = 0;
      this->Dim3.size = 0;
      
      this->baseAddress = new float[sizeOf()];
      this->deconstructable = true;
}


//************************************************************************************************
mdArray::mdArray(int lB1, int uB1, int lB2, int uB2)
// pupose:                  Set up a two dimensional mdArray object.
// pre-condition:      uB1 >= lB1, and uB2 >= lB2.
// post-condition:      A two dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf      
{
      this->dimensions = 2;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = lB2;
      this->Dim2.uprBnd = uB2;
      this->Dim3.lowBnd = 0;
      this->Dim3.uprBnd = 0;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = uB2 - lB2 + 1;
      this->Dim3.size = 0;
      
      this->baseAddress = new float[sizeOf()];
      this->deconstructable = true;
}


//************************************************************************************************
mdArray::mdArray(int lB1, int uB1, int lB2, int uB2, int lB3, int uB3)
// pupose:                  Set up a Three dimensional mdArray object.
// pre-condition:      uB1 >= lB1, uB2 >= lB2, and uB3 >= lB3.
// post-condition:      A three dimensional mdArray object will
//                              be created and set to the specified bounds.
// called by:            Client of mdArray class, changeSize.
// calls:                  sizeOf      
{// state that lowerBound must be less than upperbound.
      
      // calculate the sizes for the upper and lower Bounds

      this->dimensions = 3;

      this->Dim1.lowBnd = lB1;
      this->Dim1.uprBnd = uB1;
      this->Dim2.lowBnd = lB2;
      this->Dim2.uprBnd = uB2;
      this->Dim3.lowBnd = lB3;
      this->Dim3.uprBnd = uB3;

      this->Dim1.size = uB1 - lB1 + 1;
      this->Dim2.size = uB2 - lB2 + 1;
      this->Dim3.size = uB3 - lB3 + 1;

      this->baseAddress = new float[sizeOf()];
      this->deconstructable = true;
}


//************************************************************************************************
mdArray::~mdArray()
// pupose:                  To deconstruct an mdArray object and free up it's used memory.
// pre-condition:      
// post-condition:      the memory allocated by the declairation of baseAdress is freed up.
// called by:            ?????.
// calls:                  none      
{
      if(this->deconstructable)
            delete [] this->baseAddress;
}
0
 
nietodCommented:
That "deconstructable" flag makes me very nervious.  What is it for?
0
 
kainhartAuthor Commented:
look at the deconstructor, it only uses delete if an object is deconstructable.  It's normally deconstructable unless change size is called.  The new array in change size is non deconstructable.  But you assign the memory from that new array to the object that calles the fucntion anyway which is deconstructable. and you delete the old memory from inside the change size function. So there is no leaks.  
0
 
nietodCommented:
That is not a very good design.  There are much simpler ways of doing this that wll be safer.

Your best bet is to write a single "resizing" function  The 3 constructors and this resize function all call this private "resizing" function.  Your code will be shorter, simpler, more modular, and safer.  You will not need carry around this "deconstructable" flag which is a waste of space and an accident waiting to happen.  

Are you interested in improving it?
0
 
kainhartAuthor Commented:
ok, here is the problem.  This is part of an assignment thats due today. I just did my deep testing and my method failed big time.  Is it possible that I can change my code to do what your saying in a a short amount of time?  I'm so confused about this problem, and I have had absolutly no sleep for this night. I would appreciate it if you could explain a quick correct way to do this.  Thank you very much, both of you have been a lot of help.
0
 
kainhartAuthor Commented:
In your example above I don't understand the part where you have

float *NewArray = new float[XXXXX];  // You need to figure
  // out XXXX.  I'm not sure of the details.
0
 
nietodCommented:
>> Is it possible that I can change my code
>> to do what your saying in a a short amount of time?
That is intirely up to you.

//A sample constructor
mdArray::mdArray(int lB1, int uB1)
{
   baseAddress = NULL; // make sure there is no memory
     // for ReAllocate() to delete.
   ReAllocate(1, // one dimension
                    lB1,uB2, // 1st dimension.
                    0,0, // 2nd dimension.
                     0,0); // 3rd dimension.
};

That is pretty simple, right?  Can you write the other constructors?

// Reallocate the array.  delete the old and alocate the new
mdArray::Realloc(int NumDim,int lB1, int uB1, int lB2, int uB2, int lB3, int uB3)
{
   dimensions = NumDim;

   Dim1.lowBnd = lB1;
   Dim1.uprBnd = uB1;
   Dim2.lowBnd = lB2;
   Dim2.uprBnd = uB2;
   Dim3.lowBnd = lB3;
   Dim3.uprBnd = uB3;

   Dim1.size = uB1 - lB1 + 1;  // This should be done automatically
                               // by the dimension class.  the class should have
                               // a member function that you call to se the uppr
                               // and lower bound, and that function will also set
                               // the size automatically.  Simpler?
   Dim2.size = uB2 - lB2 + 1;
   Dim3.size = uB3 - lB3 + 1;


   // Some designs might copy data from the old array to the new one
  // here.  I guess you don't need that?
   delete [] baseAddress;  // delete old array.
   baseAddress = new float[sizeOf()];
}


Now you should be able to drop those InitWith() functions.  The changeSize() functions can just call ReAllocate().  They should be very simple.

Notice how remiving duplicate or similar code and placing it in one location makes the program smaller and simpler.  The program also becomes more reliable this way and easier to debug and easier to modify in the future.  

The suggestion about adding a set() function to the dimensions class woudl be another example of this.
0
 
kainhartAuthor Commented:
In your example above I don't understand the part where you have

float *NewArray = new float[XXXXX];  // You need to figure
  // out XXXX.  I'm not sure of the details.
0
 
nietodCommented:
That is the size of the array to be created.  Just use sizeOf() if that works.  I don't see code for it, but I assume it works.
0
 
kainhartAuthor Commented:
all my functions above. All I have planned right now is just to eliminate my deconstructor and have a mem leak.  We never learned deconstructors in school yet anyway.  Unless I can find some quick way to change this around so it works right with a deconstructor.  If I change my changeSize function like what you have above you say that should work?  is that that Idea you had with the private function or is that something else?
0
 
nietodCommented:
yes.  That reallocate() function is the provate function I was suggesting that woudl do the work of all 3 constructors and the chageSize() function.  The 3 constructors and the changeSize() function become VERY simple.  The work is all done in ReAllocate(), and that is written, or at least 99% written.
0
 
kainhartAuthor Commented:
all my functions above. All I have planned right now is just to eliminate my deconstructor and have a mem leak.  We never learned deconstructors in school yet anyway.  Unless I can find some quick way to change this around so it works right with a deconstructor.  If I change my changeSize function like what you have above you say that should work?  is that that Idea you had with the private function or is that something else?
0
 
kainhartAuthor Commented:
all my functions above. All I have planned right now is just to eliminate my deconstructor and have a mem leak.  We never learned deconstructors in school yet anyway.  Unless I can find some quick way to change this around so it works right with a deconstructor.  If I change my changeSize function like what you have above you say that should work?  is that that Idea you had with the private function or is that something else?
0
 
sumant032199Commented:
Don't give up yaaaar.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 14
  • 14
  • 8
Tackle projects and never again get stuck behind a technical roadblock.
Join Now