?
Solved

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

Posted on 2001-06-25
16
Medium Priority
?
386 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 6
16 Comments
 
LVL 30

Expert Comment

by:Axter
ID: 6225883
//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
ID: 6225892
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
ID: 6225895
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 30

Expert Comment

by:Axter
ID: 6225896
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
ID: 6225902
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
ID: 6225909
> 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
ID: 6225914
Where are you copying it now?
0
 
LVL 30

Expert Comment

by:Axter
ID: 6225917
Where in your code are you copying CComObject?
0
 

Author Comment

by:12bsure
ID: 6225919
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
ID: 6225920
> 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
ID: 6225926
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 600 total points
ID: 6225929
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
ID: 6225936
You only have to use New once, and delete once.
0
 

Author Comment

by:12bsure
ID: 6226006
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
ID: 6226024
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
ID: 6226072
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

NEW Veeam Agent for Microsoft Windows

Backup and recover physical and cloud-based servers and workstations, as well as endpoint devices that belong to remote users. Avoid downtime and data loss quickly and easily for Windows-based physical or public cloud-based workloads!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

770 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