【问题标题】:AV while iterating through hash_map?遍历hash_map时的AV?
【发布时间】:2009-09-29 17:46:17
【问题描述】:

_transaction 是我的类的私有成员变量,声明为:

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

在清理期间,我试图遍历此列表并释放任何仍未释放的对象。但是我在这里的 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: 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;
        }
    };

堆栈在 begin() 方法中显示它。有什么想法吗?

【问题讨论】:

  • 您省略的代码很好实际上是导致错误的常见原因。例如,如果您要从哈希表中删除一项并且没有正确设置 it (迭代器)(当然取决于哈希实现)。
  • 您确定您没有尝试从已删除的对象中清理地图吗?
  • 谢谢大家,我编辑了我的帖子以包含更多代码。澄清一下,在 WINDBG 内部,AV 显示在 hash_map 本身的 begin() 方法内部。
  • MyClass 为什么重要。作为练习,即使我删除了 for 循环内的部分,它仍然是 AV 的。

标签: c++ stl hashmap access-violation


【解决方案1】:

我能想到的一个可能的事情是,在您尝试遍历 hash_map 之前,您的类已经在其他地方被删除,因此 begin() 将对垃圾进行操作。值得一试...

另外 - 你的 wchar_t* 是如何被分配/释放的?您显示的代码似乎没有处理这些。我不确定这会如何在您的循环中造成麻烦,但值得考虑。

一件小事 - 你不应该需要 (MyClass*) 演员表。 hash_map 的值无论如何都应该是该类型,因此让编译器强制执行类型检查比使用显式强制转换绕过它们要好。不过,这不应该在这里产生任何影响。

【讨论】:

  • 谢谢,我确保 wchar_t* 被正确释放(从技术上讲,它们实际上是由用户交给我的,但在我的情况下它们被释放了)。我的 hash_map 不应该在其他地方删除,因为我将它声明为私有成员,它应该在堆栈上(但也许我的假设是错误的?)
  • 当然,但是如果类本身已被删除,并且您稍后尝试通过指向其旧位置的指针来访问它,则可能失败的第一件事是在 begin 中构造迭代器的哈希()。只是一个想法,因为您在此处发布的代码看起来还不错。
  • 标记此答案,因为它最接近问题。创建类时,它被创建为它的基类型,而不是我的类。因此,当它运行“清理”时,我将基类型转换为 MyClass,这给了迭代器垃圾。
【解决方案2】:

据我了解,您正在检查指针是否为 NULL,以查找可能尚未删除的“剩余”项目。但是对于您在清理阶段之前删除的项目,您是否将指针设置为 NULL?

请注意,当您删除一个对象时,指针不会自动设置为 NULL。因此,如果您不这样做,您会尝试两次删除同一个对象(因为您的 if 语句将始终为真),可能会导致访问冲突。

下面的代码是导致双重删除的示例。如果取消注释将指针设置为 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;
}

编辑: 我看到您在 for 行上遇到了错误。所以我想知道...

显然你有一个 MyClass 包含一个 _transactions 成员,它是一个以 MyClass 指针作为数据类型的哈希表。如果清理代码是在 MyClass 的成员函数内执行的,您是否可能正在删除(出于某种原因)拥有该 MyClass 实例_transactions 你在迭代吗?

在这种情况下,您可能会在 for 内的 it++ 语句中遇到错误,因为 this 对象不再存在。 (当然,错误也可能在其他地方,比如删除本身。)

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2013-06-23
      • 2012-09-17
      • 2011-09-30
      • 1970-01-01
      • 2016-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多