Solved

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

Posted on 2001-06-25
16
380 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
Salesforce Has Never Been Easier

Improve and reinforce salesforce training & adoption using WalkMe's digital adoption platform. Start saving on costly employee training by creating fast intuitive Walk-Thrus for Salesforce. Claim your Free Account Now

 
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 150 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

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Problem with SqlConnection 4 184
PHPStorm debugging issues 1 72
SSRS troubles 4 84
How do I get Window Title of all opened process? 4 37
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…
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 NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

749 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