Paul
Paul

Reputation: 275

CAtlArray strange behavior using SetCount

I am having a strange issue with a CAtlArray. It works as expected if I use the Add function to add an element to the array. However, if I use SetCount before adding any elements, the program crashes. Strangely, it only works if I add elements directly with the [] operator (I know I know, the documentation says to only use [] to get an element, not to set one). I have been checking that SetCount returns true and it does. Unfortunately, I can't get much debug info easily because this is a dll hooking another process. I can only debug by printing ...

I am wondering if this is typical behavior/if I am missing something (the documentation sucks, google did not return any helpful results, and the ATL code is hard for me to read/follow). My first thought was that SetCount(X) might have some behavior like calling Add() X times and shouldn't be called unless it is expanding the array, but SetAt doesn't work with SetCount either.

Any ideas about what might be going on here?

EDIT:

CAtlArray<MyClass*> arr;

...

size_t initialCount = 10;    

if ( arr.SetCount(initialCount) ) { 
  for ( int i = 0; i < initialCount; i++ ) {
    //arr.Add( new MyClass );//Does NOT work
    //arr.SetAt( i, new MyClass );//Does NOT work
    arr[i] = new MyClass;//This works
  }
}

EDIT 2:

I forgot to mention, I also tried using the GetData method but it didn't work either:

MyClass **pData;

if ( arr.SetCount(initialCount) ) {
  pData = arr.GetData();
  for ( int i = 0; i < initialCount; i++, pData++ ) {
    *pData = new MyClass;
  }
}

Upvotes: 0

Views: 283

Answers (1)

Roman Ryltsov
Roman Ryltsov

Reputation: 69632

All the three attempts to add elements DO work, but they don't do exactly the same thing, and - more important - the dangerous option does not crash the application and only creates a condition that causes crash later.

//arr.Add( new MyClass );//Does NOT work
//arr.SetAt( i, new MyClass );//Does NOT work
arr[i] = new MyClass;//This works

Let's see what the they actually do:

  • SetCount adds 10 NULL elements to the array
    1. following Add leaves those ten nulls and adds your instances as 11th, 12th and on
    2. following SetAt replaces NULLs with your instances
    3. following indexed set replaces NULLs with your instances in the same way as #2 above

So items #2 and #3 do "work" and item #1 does a different thing: the array has 20 items and if you later attempt to access the elements, you hit NULLs where you expect to have valid pointers.

Have a look at small application that prints element count (you can see you have 10 or 20 elements), and then does element checking to verify if all elements of the array are "valid".

#include "stdafx.h"
#include <atlcoll.h>

class MyClass
{
private:
    INT m_nValue;

public:
    MyClass() :
        m_nValue(0xDEADC0DE)
    {
    }
    VOID Check()
    {
        ATLASSERT(m_nValue == 0xDEADC0DE);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    CAtlArray<MyClass*> arr;
    size_t initialCount = 10;    
    if(arr.SetCount(initialCount)) 
    { 
        for( int i = 0; i < initialCount; i++ ) 
        {
            arr.Add( new MyClass );//Does NOT work
            //arr.SetAt( i, new MyClass );//Does NOT work
            //arr[i] = new MyClass; //This works
        }
    }
    _tprintf(_T("arr.GetCount() %d\n"), arr.GetCount());
    for(SIZE_T nIndex = 0; nIndex < arr.GetCount(); nIndex++)
        arr[nIndex]->Check();
    return 0;
}

An easier way to put elements to the array is as follows:

    size_t initialCount = 10;    
    //if(arr.SetCount(initialCount)) -- not needed
    { 
        for( int i = 0; i < initialCount; i++ ) 
        {
            arr.Add( new MyClass );
        }
    }

Upvotes: 1

Related Questions