【问题标题】:EXC_BAD_ACCESS when trying to delete valid pointer (xcode c++)尝试删除有效指针时的 EXC_BAD_ACCESS (xcode c++)
【发布时间】:2012-01-05 00:14:03
【问题描述】:

我有一个名为 OrdinalObjectList 的模板类,它只是一个带有 int 键和对象指针的映射。它的目的是提供可以通过序号键访问的对象指针的集合。这是课程:

template <typename O>
class OrdinalObjectList {

public:
    std::map<int, O*> List;
    OrdinalObjectList() {};
    virtual ~OrdinalObjectList() 
    {
        // Need to delete the objects in the map
        typename std::map<int, O*>::iterator i;
        for (i = List.begin(); i != List.end(); i++)
        {
            O* d = i->second;
            delete d;
        }
    };

在破坏 OrdinalObjectList 时,析构函数循环遍历映射并删除对象。到目前为止,这一直运行良好,但是在删除集合中两个对象中的第二个时,它当前收到 EXC_BAD_ACCESS 错误。

第一遍 d 是 'FSCE::Customer' * 0x10088e600,删除没有问题。在第二遍中,d 是 'FSCE::Customer' * 0x100897e00,当 delete'd 会导致 EXC_BAD_ACCESS。我可以在调试器中访问第二个“d”的成员。即d->lifeid int 2,表示FSCE::Customer对象是一个有效的对象,而'd'是一个有效的指针。

接下来我应该采取哪些步骤来追查 EXC_BAD_ACCESS 的原因?

【问题讨论】:

  • 使用用于检测空闲后访问的工具运行代码,例如valgrind。最有可能的是,之前的 malloc/free/new/delete 操作正在破坏堆,导致此删除失败。
  • 我现在正在这样做。用于 OSX 的 Valgrind 不完整,但我会看看它有什么报告。我还应该注意,如果我单线程运行程序不会发生错误,它只会在多线程处理后发生。我想知道处理线程是否没有正确分离并且以某种方式“锁定”对象。

标签: c++ xcode gcc exc-bad-access delete-operator


【解决方案1】:

我无法确定,但您是否有可能删除第 1 项和(不存在的)第 2 项,而不是第 0 项和第 1 项?确保您删除的是您认为要删除的内容。

【讨论】:

  • 不,它正在删除正确的项目。我刚刚注意到,如果我将处理线程(上面的代码在主线程中运行)减少到 1,我不会得到错误,并且正确的对象被删除而没有问题。
【解决方案2】:

EXC_BAD_ACCESS 可以通过启用僵尸对象轻松追踪。

对于 XCode 4.x,请参阅 How do I set up NSZombieEnabled in Xcode 4?

对于其他版本的 XCode,您可以在 Internet 上找到它。

【讨论】:

  • 我以为 NSZombieEnabled 仅适用于 Objective-C,我没有意识到它可以为 c++ 启用。看看这个:cocoabuilder.com/archive/cocoa/… 使用受保护的 malloc 可能会更好。感谢您的回复。
【解决方案3】:

编辑:以下不正确。

并不是一个真正的答案,但是当我将线程数减少到 4 个时,问题就消失了。之前我将线程数设置为8,boxen是Core i7,它是4核超线程。

我只能假设超线程存在问题,无论是在 OSX 内核还是 LLVM 中。我将优化设置为 O3,在某些时候我会关闭优化,看看它是否适用于 8 个线程,但是与此同时,4 个线程只比 8 个慢 10%,所以我会坚持下去,这样我就可以进步了。

问题在于我要删除的对象中有一个大数组。数组在构造函数中创建并在析构函数中删除,类似这样(数据成员名称已更改):

Matrix::Matrix(int maxa, int maxb, int maxc) 
{
  asize = maxa;
  bsize = maxb; 
  csize = maxc;
  matrixsize = a * b * c;
  matrix = new double [matrixsize];
}
Matrix::~Matrix()
{
  delete [] matrix;
}

到目前为止一切都很好,但是在设置矩阵中的值时我遇到了一个错误。

void Matrix::SetValue(int a,int b,int c,double value)
{
  int index = (a * asize) + (b * bsize) + c;
  matrix[index] = value;
}

另一部分代码中设置“maxc”的错误意味着有时索引会大于矩阵大小,这是我通过添加检查并抛出来发现的。

void Matrix::SetValue(int a,int b,int c,double value)
{
  int index = (a * asize) + (b * bsize) + c;
  if (index >= matrixsize) throw;
  matrix[index] = value;
}

这将导致访问构造函数中分配的内存之外的内存,并且当调用删除时,会引发 EXC_BAD_ACCESS 错误。奇怪的是为什么 EXC_BAD_ACCESS 在执行期间没有在 Matrix::SetValue 中引发,但我想答案与没有针对堆管理器的内存边界检查数组索引偏移量的边界有关。如果有人能说明我会最感兴趣,但现在,这个答案适用于任何从网络搜索中找到这个答案的人。

【讨论】:

  • 语言没有索引检查。操作系统级内存保护也仅适用于 MMU 页面边界,例如它仅在尝试访问未分配给您的 MMU 页面时触发。可能发生的情况是您覆盖了通常位于分配的堆块之前的堆单元元数据,具体取决于实现。因此,当释放带有损坏元数据的块时,会导致访问错误。
  • 另请注意,您的索引计算可能不是您想要的 - 例如对于 3x3x3 矩阵,(1,2,3) 和 (2,1,3) 共享相同的索引。
  • 对不起,我是从内存中输入的,实际上是:(a * bsize * csize) + (b * csize) + c; .感谢您对 MMU 页面边界的评论。
猜你喜欢
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 2011-09-18
  • 2013-06-01
  • 2010-09-08
  • 2010-10-07
  • 2018-05-14
相关资源
最近更新 更多