Solved

ATL/COM: How to create/maintain an array of CComObjects?

Posted on 2001-06-25
16
369 Views
Last Modified: 2013-12-14
Hi,

I am changing the implementation of our own grid control form using an array of structs for all cells to using an array of Com objects. I have a working solution, but I don't seem to be able to delete the objects I created, which shows in practice as a huge resource/memory leak.
I would like them to be in an array, but if there's a better/easier solution I will certainly look into it (but not MFC!). Furthermore, in the current implementation I create every object anew, but I guess copying/cloning to be much faster. It's probably easy to implement, I just don't know how.

This is how my declaration looks:
CComObject<CFastGridCell>*     m_lpCellsProp;

This is how it is updated when the dimensions of the grid change:
m_lpCellsProp = new CComObject<CFastGridCell>[m_cols * m_rows + 1];
for(int irow=1; irow<=m_rows; irow++)
{
    for(int icol=1; icol<=m_cols; icol++)
    {
        int id = getCellID(irow, icol);
        m_lpCellsProp[id] = new CComObject<CFastGridCell>();
        //do some things on the object, like:
        m_lpCellsProp[id].put_Default(props);
    }
}

I have no idea how the delete statement should like. I didn't get any to work. Maybe I do it all wrong. I never worked with arrays of some template type, let alone arrays of CComObject types. If someone knows how to do the same with multidimensional arrays, it'll be even more appreciated.

Btw, the above implementation works well in debug builds, but gives an access denied error after the first tens of object's constructs/destructs.

Btw2, the idea is to provide some kind of aggregation, but again, I never did that, except for simple objects like IFont and such.

Thanks in advance for any ideas,
12Bsure corp.
0
Comment
Question by:12bsure
  • 10
  • 6
16 Comments
 
LVL 30

Expert Comment

by:Axter
Comment Utility
//Example delete
for(int irow=1; irow<=m_rows; irow++)
{
   for(int icol=1; icol<=m_cols; icol++)
   {
       int id = getCellID(irow, icol);
       delete m_lpCellsProp[id];
   }
}

0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
I think your code should look like the following for initialization:
m_lpCellsProp = new CComObject<CFastGridCell>[m_cols * m_rows + 1];
for(int irow=0; irow<=m_rows; irow++)
{
   for(int icol=0; icol<=m_cols; icol++)
   {
       int id = cols*m_rows + irow;
       m_lpCellsProp[id] = new CComObject<CFastGridCell>();
       //do some things on the object, like:
       m_lpCellsProp[id].put_Default(props);
   }
}

//Example delete
for(int irow=0; irow<=m_rows; irow++)
{
   for(int icol=0; icol<=m_cols; icol++)
   {
       int id = cols*m_rows + irow;
       delete m_lpCellsProp[id];
   }
}

0
 

Author Comment

by:12bsure
Comment Utility
Which means that I cannot simply use a call similar to?:
delete [] somevar;

But is the space allocated with the following statement deallocated properly?
m_lpCellsProp = new CComObject<CFastGridCell>[m_cols * m_rows + 1];
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
I missed the greater or equal sign.  I took them out on the following code:

m_lpCellsProp = new CComObject<CFastGridCell>[m_cols*m_rows];
for(int irow=0; irow<m_rows; irow++)
{
  for(int icol=0; icol<m_cols; icol++)
  {
      int id = cols*m_rows + irow;
      m_lpCellsProp[id] = new CComObject<CFastGridCell>();
      //do some things on the object, like:
      m_lpCellsProp[id].put_Default(props);
  }
}

//Example delete
for(int irow=0; irow<m_rows; irow++)
{
  for(int icol=0; icol<m_cols; icol++)
  {
      int id = cols*m_rows + irow;
      delete m_lpCellsProp[id];
  }
}

0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
Now that I come to think of it, that code is wrong too.

You have to do an individual delete, and then do a delete for the pointers.

Give me a minute, and I'll see if I can post a correct version.
0
 

Author Comment

by:12bsure
Comment Utility
> int id = cols*m_rows + irow;
Basically that is what I did in getCellID:
long CFastGrid::getCellID(long Row, long Col)
{
     if(Row > m_rows || Col > m_cols || Row < 1 || Col < 1)
          return (0);

     long iRet = (Row - 1) * m_cols + Col;
     if(iRet > m_rows * m_cols)
          return (0);
     else
          return(iRet);
}


Do you have any idea how to copy the CComObject? Because this way it's dreadfully slow!
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
Where are you copying it now?
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
Where in your code are you copying CComObject?
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:12bsure
Comment Utility
Ah, now I see it. Sorry, I didn't look close enough. You create a zero-based array and I start (deliberately) on one. The reason is, as you can see from getCellID, that I want a dummy-cell to be returned to the client when the client requests the wrong cell. I also use it in the implementation when I don't know for sure I get a cell (like on mouseover). It eases my programming a bit.
0
 

Author Comment

by:12bsure
Comment Utility
> Where in your code are you copying CComObject?
I don't. I haven't got a clue on how to do it. IFont has a Clone method, maybe I need to implement my own, but I hope there's an easier way.
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
This is an example using foo and foofoo as the classes:

class foofoo
{
public:
     int x;
};

template<class T>
class foo
{
public:
     foo(){};
     T data;
};

int main(int argc, char* argv[])
{
     int m_cols = 32;
     int m_rows = 16;
     foo<foofoo>* m_lpCellsProp = new foo<foofoo>[m_cols * m_rows];
     for(int irow=0; irow<m_rows; irow++)
     {
          for(int icol=0; icol<m_cols; icol++)
          {
               int id = icol*m_rows + irow;              
               //do some things on the object, like:
               m_lpCellsProp[id].data.x = 3;
          }
     }
     return 0;
}
0
 
LVL 30

Accepted Solution

by:
Axter earned 150 total points
Comment Utility
I forgot the delete:

class foofoo
{
public:
     int x;
};

template<class T>
class foo
{
public:
     foo(){};
     T data;
};

int main(int argc, char* argv[])
{
     int m_cols = 32;
     int m_rows = 16;
     foo<foofoo>* m_lpCellsProp = new foo<foofoo>[m_cols * m_rows];
     for(int irow=0; irow<m_rows; irow++)
     {
          for(int icol=0; icol<m_cols; icol++)
          {
               int id = icol*m_rows + irow;              
               //do some things on the object, like:
               m_lpCellsProp[id].data.x = 3;
          }
     }
     delete [] m_lpCellsProp;
     return 0;
}


0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
You only have to use New once, and delete once.
0
 

Author Comment

by:12bsure
Comment Utility
I'm glad it's all that simple after all. I've had so many different tries that it never occurred to me that I could leave the tedious new-statements in the loop. A few hours ago I was hopelessly lost in the intricacies of ATL/COM, but now everything looks simple and easy again! Thanks a lot!

FYI, this is the current implementation. I still have a small resource leak, but not that huge anymore as I had before. It's probably in another part of my code.

void CFastGrid::setDimensions(long irows, long icols)
{

     if(((m_rows) && (m_cols))          //Only the first call these are zero;
          || (!irows && !icols))          //Only the last call these are zero
     {
          delete [] m_lpCellsProp;
          if(!irows && !icols)          //We are in the destructor, bail out
               return;
     }
     m_rows = irows;
     m_cols = icols;

     m_lpCellsProp = new CComObject<CFastGridCell>[m_cols * m_rows + 1];

     ATLASSERT(m_lpCellsProp);
     for(int irow=1; irow<=m_rows; irow++)
     {
          for(int icol=1; icol<=m_cols; icol++)
          {
               int id = getCellID(irow, icol);
               m_lpCellsProp[id].setDefaults(val1, val2 valX);
          }
     }

}

PS: The speed penalty from all the new-statements is completely gone. Now it's fast again!

PS2: It's good to know that the code looks like I learned my basics, instead of the clumsy workarounds and buggy code I ended up with.

Thanks alot for your help!
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
On the for() loop, shouldn't it start at zero?
With it starting at 1, that would mean that id, would never equal to zero, and since you have a zero based variable, that would mean that the first col and row, would never get filled.

I'm not sure if you account for that in your getCellID() function.

Everything else looks good.
0
 

Author Comment

by:12bsure
Comment Utility
No. At least, I think I did it correctly. Maybe you missed on one of my comments (some went so fast). For convenience, I'll repeat it here:

1. 06/25/2001 06:03PM PST
> int id = cols*m_rows + irow;
Basically that is what I did in getCellID:
long CFastGrid::getCellID(long Row, long Col)
{
    if(Row > m_rows || Col > m_cols || Row < 1 || Col < 1)
         return (0);

    long iRet = (Row - 1) * m_cols + Col;
    if(iRet > m_rows * m_cols)
         return (0);
    else
         return(iRet);
}

2. 06/25/2001 06:07PM PST
Ah, now I see it. Sorry, I didn't look close enough. You create a zero-based array and I start (deliberately)
on one. The reason is, as you can see from getCellID, that I want a dummy-cell to be returned to the
client when the client requests the wrong cell. I also use it in the implementation when I don't know
for sure I get a cell (like on mouseover). It eases my programming a bit.




As you can see, I use the very first of the array as some kind of special purpose cell.

I'll get you the points shortly. Again: thanks a lot!
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now