Thread: dynamic memory alloccation & returning objects

  1. #1
    Registered User
    Join Date
    Apr 2005
    Posts
    4

    dynamic memory alloccation & returning objects

    hello
    i wrote a code the other day...wherein i hav a class MATRIX. and i hav a function add() to add matrices and return the result. the object of matrix is constructed using a double pointer to an integr(int**) and the new operator.
    a destructor destroys the objects created using the delete operator.

    i want to return the result matrix frm the function but this aint happenin..i think its coz of the destructor..it could also be because if the m3 object in main is not built using new.


    anything help in this regard ll be appriciated..i hav posted the program below.

    Code:
    #include<iostream.h> 
    #include<conio.h> 
    
    class MATRIX 
       { 
       private: 
           int row,col; 
           int** x; 
       public: 
          //constructors 
    
          MATRIX(); 
          MATRIX(int r,int c); 
          ~MATRIX(); 
          //methods 
          void read(); 
                                    MATRIX add(MATRIX M2); 
          void display(); 
       }; 
    
    int main() 
    { 
    clrscr(); 
    MATRIX m1(2,2),m2(2,2); 
    m1.read(); 
    m2.read(); 
    
    
    MATRIX m3; 
    
        
    m3=m1.add(m2); 
    m3.display(); 
    getch(); 
    return 0; 
    } 
    
    
    MATRIX::MATRIX(int r, int c) 
    { 
    row=r;col=c; 
    x=new int* [row]; 
    for(int k=0;k<row;k++) x[k]=new int [col]; 
    
    } 
    
    void MATRIX::read() 
    { 
    cout<<"ENTER THE ELEMENTS"<<endl; 
    for(int i=0;i<row;i++) 
       { 
       for(int j=0;j<col;j++) 
          { 
          cin>>x[i][j]; 
          } 
       } 
    } 
    
    
    
    MATRIX::MATRIX() 
    { 
    } 
    
    
    
    MATRIX::~MATRIX() 
    { 
    cout<<endl<<"DESTRUCTOR CALLED"<<endl; 
    for (int k=0;k<row;k++) delete x[k]; 
    delete x; 
    } 
    
    MATRIX MATRIX::add(MATRIX m2) 
    { 
    MATRIX m(row,col); 
    if(row==m2.row && col==m2.col) 
       { 
       for(int i=0;i<row;i++) 
          { 
          for(int j=0;j<col;j++) 
             { 
             m.x[i][j] =x[i][j]+m2.x[i][j]; 
             } 
          } 
       } 
    else   cout<<"Add not applicable"<<endl; 
    m.display(); 
    return m; 
    } 
    
    
    void MATRIX::display() 
    { 
    cout<<endl<<endl; 
    for(int i=0;i<row;i++) 
       { 
       for(int j=0;j<col;j++) 
          { 
          cout<<x[i][j]<<" "; 
          } 
          cout << endl; 
       } 
    }
    thankin you

  2. #2
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    You need to have a proper copy constructor. If not both pointers will point at the same memory adn you'll get problems at deallocation. Also, call delete[] not delete on memory allocated by new[].
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  3. #3
    Registered User
    Join Date
    Apr 2005
    Posts
    4
    can i get a little more clarification on both the copy constructor and the delete operator...sorry for the trouble i m a newbie..

  4. #4
    Senior Member joshdick's Avatar
    Join Date
    Nov 2002
    Location
    Phildelphia, PA
    Posts
    1,146
    http://faq.cprogramming.com/cgi-bin/...&id=1043284351

    There's an entry in the FAQ on using new and delete.

  5. #5
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    1) All cap names, like MATRIX, are by convention used for constants. On the other hand, class names start with one cap: Matrix. Surprisingly enough, when you are used to that, an all caps class name like MATRIX is hard on the eyes.

    2) Copy Constructor:

    Any time you call a function and send it some arguments, copies of the arguments are made for the function. The same thing happens when you return something from a function: a copy is made, and the copy is returned. In your add() function, you do this:
    Code:
    MATRIX MATRIX::add(MATRIX m2) 
    { 
    	MATRIX m(row,col); 
    	...
    	...
    	return m; 
    }
    When you return m, an m copy is made and returned. Then, when the function ends, m is destroyed.

    The copy constructor comes into play because the copy constructor is what's used to make the m copy that is returned. Classes come with a lot of default stuff: you may already know about the default constructor and default destructor, but a class also comes with a default copy constructor. The default copy constructor that is supplied is said to make 'shallow' copies of the object. What that means is that it just copies everything exactly as it is in the original object. So, if you have a pointer in your original object, then the copy will have the exact same address and point to the same place in memory. In your add() function, the m object you created has a pointer in it:
    Code:
    class MATRIX 
    { 
    private: 
       int row,col; 
       int** x;
    However, if you remember, I said before that when the add() function ends, m is destroyed:
    Code:
    MATRIX MATRIX::add(MATRIX m2) 
    { 
    	MATRIX m(row,col); 
    	...
    	...
    	return m; 
    }
    That means the destructor you defined is called for m, and the memory that m's pointer points to is freed back to the system. But, the m copy that is returned is an exact copy of m, so the m copy has a copy of the m pointer. Therefore, the m copy will have a pointer that points to the memory that is no longer valid.

    To solve that problem, you need to define a copy constructor that makes a 'deep' copy, i.e. instead of just copying m's pointer, your copy constructor needs to use m's pointer to get the actual data at that address, copy the data, and then assign it to a new pointer. That way, when m is destroyed, the m copy will have a pointer that points to a different location in memory, and therefore the memory will remain intact.

    A copy constructor has a special form just like a regular constructor does: it doesn't return anything, and it takes a constant reference to the class as it's only parameter:

    Matrix(const Matrix& rm)

    It's imperative that the parameter be a reference type--otherwise a copy of the object would need to be made for the copy constructor function, which in turn would require a call to the copy constructor, etc., etc., and you end up getting an infinite chain of calls to the copy constructor.

    2) Deleting:

    Whenever you use new, you should always use delete to free up the memory when you are done with the memory. And, whenever you use 'new []', you need to use 'delete []'. What that means is: when you use "new []" to create an array, then when you delete, you use 'delete []' to delete the whole array. On the other hand, if you just used "new" to dynamically create the memory, then you just use "delete". In addition, the number of new's should equal the number of delete's: if you count the number of times you used new, there should be an equal number of deletes.

    If you look at your example, you used 'new []' once to create the array of pointers, and you used 'new []' for each pointer in the array. So, to delete all the memory, you need to do this:
    Code:
    for(int j = 0; j < rows; j++)
    {
    	delete [] x[j]; //deletes each one dimensional array
    }
    
    delete [] x;  //deletes the array of pointers
    Last edited by 7stud; 04-21-2005 at 09:48 AM.

  6. #6
    Registered User
    Join Date
    Apr 2005
    Posts
    4
    thanks guys... that solved my problem... hoping to interact and learn a lot from u people...thanks again

  7. #7
    Registered User
    Join Date
    Apr 2005
    Posts
    4
    wwops....sorry 2 bring up this topic again...but the problem aint completely solved

    i wrote the copy constructor
    Code:
    MATRIX::MATRIX(const MATRIX &m)//copy constructor
    {
    row=m.row;
    col=m.col;
    
    x=new int* [row];
    for(int k=0;k<row;k++) x[k]=new int [col];
    
    for(int i=0;i<row;i++)
    	{
    	for(int j=0;j<col;j++) x[i][j]=m.x[i][j];
    	}
    }
    now in main in declare
    Code:
    MATRIX m3;
    m3=m1.add(m2);
    the program give me a nonsense result.

    if i try
    Code:
    MATRIX m3=m1.add(m2);
    it gives me the right result

    i cant explain this?
    i need to make the program in the former method
    also i think i shud mention that i hav a default constructor that does nothing. ie
    Code:
    MATRIX::MATRIX()
    {
    }
    thankin you
    Last edited by haditya; 04-21-2005 at 09:47 PM.

  8. #8
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    If you initialize the object as in your second example, it will call the copy constructor. However, the first example will call an assignment operator, and since you didn't write your own it is probably a shallow copy. Try writing your own overloaded = operator.
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  9. #9
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    The copy constructor is called when:

    1) You create an object of your class that calls a constructor whose parameter is another object of the class, e.g.:

    Matrix m1;
    Matrix m2(m1);

    2) when an object is passed to a function by value, or

    3) when an object is returned from a function by value.

    Apparently this:

    MATRIX m3=m1.add(m2);

    falls under 1). That statement is essentially equivalent to:

    MATRIX m3 = m4;

    and for some reason that is equivalent to:

    MATRIX m3(m4);

    so the copy constructor is called. However, in the other example:

    MATRIX m3;
    m3=m1.add(m2);

    that is essentially the same thing as:

    MATRIX m3; //object created
    m3 = m4; //assignment operator called

    You have discovered another one of the defaults that comes with a class: the default assignment operator. Like the default copy constructor, the default assignment operator makes a 'shallow' copy. You need to define an op=() function for your class to make a deep copy. It should return a reference to the left hand side object(*this), and it should accept a reference parameter:

    Matrix& op=(const Matrix& rhs); //'const' just says the function cannot modify the argument

    The first thing you need to do is check if the left and the right hand side of the equals sign are the same object(if *this==rhs), and if so just return the left hand side. The reason you need to return an object is so statements like this work:

    m1 = m2 = m3;

    You might also need to delete some memory depending on what you do. In these lines:

    MATRIX m3;
    m3=m1.add(m2);

    You create m3 and then you assign it the result of your add() function. The default assignment operator will just copy the pointer in the Matrix object returned by add() into m3's pointer, which overwrites m3's pointer and therefore you lose your pointer to the memory allocated originally for m3. That is a memory leak.

    The bottom line is that whenever you dynamically allocate memory in a class, you need to implement a copy constructor, an assignment operator, and a destructor.
    Last edited by 7stud; 04-22-2005 at 12:12 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic memory allocation.
    By HAssan in forum C Programming
    Replies: 3
    Last Post: 09-07-2006, 05:04 PM
  2. Why use Dynamic Memory
    By appleGuy in forum C++ Programming
    Replies: 11
    Last Post: 08-28-2006, 02:46 PM
  3. dynamic memory deletion via function
    By starkhorn in forum C++ Programming
    Replies: 4
    Last Post: 08-25-2004, 09:11 AM
  4. Dynamic Memory Allocation for fstream (binary)
    By kuphryn in forum C++ Programming
    Replies: 2
    Last Post: 12-12-2001, 10:52 AM
  5. dynamic memory allocation and returning pointers
    By sballew in forum C Programming
    Replies: 7
    Last Post: 11-03-2001, 03:21 PM