简体   繁体   English

通过hash_map迭代时的AV?

[英]AV while iterating through hash_map?

_transaction is a private member variable of my class, declared as: _transaction是我的类的私有成员变量,声明为:

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行上得到了一个AV:

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? 回复:什么是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. 堆栈将其显示在begin()方法中。 Any ideas? 有任何想法吗?

As I understand you're checking your pointer against NULL for the "remaining" items that might have not been deleted yet. 据我了解,您正在针对NULL来检查可能尚未删除的“剩余”项目的指针。 But for the items you delete before your cleanup stage, do you set the pointer to NULL? 但是对于在清理阶段之前删除的项目,是否将指针设置为NULL?

Notice that when you delete an object the pointer is not automatically set to NULL. 请注意,删除对象时,指针不会自动设置为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. 因此,如果您不这样做,则尝试两次删除同一对象(因为if语句始终为true),这可能会导致访问冲突。

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. 如果取消注释将指针设置为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. 编辑:我看到您正完全为for上得到错误。 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. 显然,您有一个包含_transactions成员的MyClass ,该成员是一个以MyClass指针作为数据类型的哈希表。 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? 如果清理代码是在MyClass的成员函数中执行的,是否有可能由于某种原因而删除了拥有要迭代的_transactionsMyClass实例?

In this case you could get an error at it++ statement inside the for since the this object no longer exists. 在这种情况下,您可能会因为for对象中的it ++语句而出错,因为对象不再存在。 (Naturally, the error could be somewhere else too, like on the delete itself.) (自然,错误也可能在其他地方,例如在删除本身上。)

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. 我可能想到的一件事是,在尝试遍历hash_map之前,您的类已在其他地方删除,因此begin()将对垃圾进行操作。 Worth a check... 值得一看...

Also - how are your wchar_t*'s getting allocated/freed? 另外-您的wchar_t *如何分配/释放? 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. 一件小事-您不需要(MyClass*)强制转换。 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. hash_map的值无论如何都应该是该类型的,因此让编译器强制执行类型检查比使用显式强制转换绕过它们更好。 That shouldn't be making any difference here though. 但是,这在这里应该没有任何区别。

确保在for循环之后调用_transactions.clear()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM