views:

235

answers:

3

_transaction is a private member variable of my class, declared as:

public:
    typedef stdext::hash_map<wchar_t*, MyClass*, ltstr> transaction_hash_map; 
private:
    transaction_hash_map _transactions;

During cleanup I am trying to iterate through this list and free up any objects still unfreed. However I am getting an AV on the for line here:

for (transaction_hash_map::const_iterator it = _transactions.begin(); it != _transactions.end(); it++)
{ 
            MyClass* item = (MyClass*)it->second;

 if (item != NULL)
 {
  item->End();
  delete item;
 }  
}

Re: What is ltstr?

private:
    struct ltstr
    {
        enum
        {
            bucket_size = 8,
            min_buckets = 16
        };

        bool operator()(wchar_t* s1, wchar_t* s2) const
        {
            return wcscmp( s1, s2 ) < 0;
        }

        size_t operator()(wchar_t *s1) const
        {
            size_t  h = 0;

            wchar_t *p = const_cast<wchar_t*>(s1);
            wchar_t zero = L'\0';

            while ( *p != zero ) h = 31 * h + (*p++);

            return h;
        }
    };

The stack shows it inside the begin() method. Any ideas?

A: 

As I understand you're checking your pointer against NULL for the "remaining" items that might have not been deleted yet. But for the items you delete before your cleanup stage, do you set the pointer to NULL?

Notice that when you delete an object the pointer is not automatically set to NULL. So if you're not doing that you're trying to delete the same object twice (because your if statement will always be true), what could cause an access violation.

The code below is an example that causes a double deletion. It can be fixed if you uncomment the line that sets the pointer to NULL.


#include <cstddef>

struct Item {};

int main()
{
  Item * p = new Item();
  delete p;

  //If you don't make the pointer null...
  //p = NULL;

  if (p != NULL)
      //You delete the object twice.
      delete p;
}

EDIT: I see you're getting the error exactly on the for line. So I'm wondering...

Apparently you have a MyClass that contains a _transactions member, which is a hash table with MyClass pointers as the data type. If the clean up code is performed inside a member function of MyClass, is it possible that you're deleting (for some reason) the MyClass instance that owns the *transactions you're iterating?

In this case you could get an error at it++ statement inside the for since the this object no longer exists. (Naturally, the error could be somewhere else too, like on the delete itself.)

ltcmelo
A: 

One possible thing I can think of is that your class has already been deleted elsewhere before you try to iterate through the hash_map, and thus begin() will be operating on garbage. Worth a check...

Also - how are your wchar_t*'s getting allocated/freed? The code you've shown doesn't appear to be dealing with those. I'm not sure how that would cause trouble in your loop, but it's worth thinking about.

One minor thing - you shouldn't need the (MyClass*) cast. The hash_map's values should be of that type anyway, so it's nicer to let the compiler enforce type checks than to possibly bypass them with an explicit cast. That shouldn't be making any difference here though.

Peter
Thanks, I ensured the wchar_t*'s are being freed properly (they are actually handed to me by the user technically, but in my case they are freed). My hash_map shouldn't be deleted elsewhere, as I am declaring it as a private member, it should be on the stack (but maybe my assumption is wrong?)
esac
Granted, but if the class itself has been deleted and you later try to access it through a pointer to its old location, it's possible that the first thing which might fail is the hash constructing an iterator in begin(). Just a thought since the code you posted here looks pretty much okay.
Peter
Marking this answer since it was closest to the problem. When the class was being created, it was being created as its base type rather than my class. So when it was running 'cleanup' I was casting the base type to MyClass which gave the iterator garbage.
esac
A: 

Make sure to call _transactions.clear() after the for loop.

Andre