0

每次调用析构函数时,我都会收到一条奇怪的消息。由于我的私有变量之一是动态分配的数组(int *member;),我这样写析构函数:

ClassSet::~ClassSet(){delete []member;}

每次ClassSet调用析构函数时,我都会收到一条错误消息:

Windows 已在 Hw1.exe 中触发断点。

这可能是由于堆损坏,这表明 Hw1.exe 或其已加载的任何 DLL 中存在错误。

这也可能是由于用户在 Hw1.exe 具有焦点时按 F12。

全班:

class ClassSet
{
  public:
    ClassSet(int n = DEFAULT_MAX_ITEMS);
ClassSet(const ClassSet& other);
ClassSet &operator=(const ClassSet& other);
~ClassSet();
  private:
    int size;
int *member;
 };

ClassSet::ClassSet(int n){
   size = n;
   member = new int[n];
}

ClassSet::ClassSet(const ClassSet& other){
    int i = 0;
    this->size = other.size;
member = new int [capacity];
while (i<size)
{
    this->member[i] = other.member[i];
    i++;
}
 }

 Multiset& Multiset::operator=(const Multiset &other)
 {
    if (&other == this){return *this;}
this->size = other.size;
int i = 0;
    delete [] member;
    member = new int[size];
while (i<other.size)
{
    this->member[i] = other.member[i];
    i++;
}
return *this;
}

知道这个析构函数有什么问题吗?

4

4 回答 4

4

您未能实施(或实施不正确)ClassSet::ClassSet(const ClassSet&)或之一ClassSet::operator=(const ClassSet&)

换句话说,你违反了三法则

然而,最好的解决方案可能不是实现它们,而是改变您为动态数组分配空间的方式。不要使用new[]and delete[],而是尝试用 . 替换该成员std::vector<>

于 2013-01-21T20:57:46.823 回答
3

堆损坏通常是事后检测到的。它可能与您的析构函数有关,或者正如我所见,可能在堆访问发生错误之前发生。

基本上“检测到堆损坏”仅仅意味着在给定的堆访问时,Windows 确定堆的当前状态不一致/无效。前一阵子出了点事。

这些错误很难追踪。堆损坏的一个常见原因是双重删除,您无意中删除了两次。这可能指向更深层次的问题,即数据如何围绕代码和设计进行复制。

正如其他人所说,当您没有复制动态内存的适当复制构造函数/赋值运算符时,可能会发生这种情况。“复制”会删除您的记忆,然后再次删除初始类,从而导致双重删除。

于 2013-01-21T20:58:21.240 回答
1

如果您发布了实际代码,那么我认为问题出在:

ClassSet::ClassSet(const ClassSet& other){
    int i = 0;
    this->size = other.size;
    member = new int [capacity];  // <--- what is capacity?
    while (i<size)
    {
        this->member[i] = other.member[i];
        i++;
    }
}

您正在根据capacityother.size. 如果capacity小于size复制元素的循环将破坏堆。

假设这是一个学术练习,一旦你解决了这个问题,你应该研究用于此类类的复制/交换习语,以确保异常安全。

如果这不是学术练习,那么您应该查看std::vector图书馆提供的其他容器。

于 2013-01-21T22:34:28.277 回答
0

这个问题很常见。默认的复制构造函数等价于

ClassSet(const ClassSet& other) {
    size = other.size;
    member = other.member;
}

这样做的问题是,当一个实例ClassSet被复制时,原始实例和新实例都持有一个指向member. 两个析构函数都会释放member,导致您看到的双重释放问题。

例如,

{
    ClassSet a
    ClassSet b(a); // assert(b.member == a.member)
} // At this point, both a and b will free the same pointer.

您可以通过不允许复制或移动指针而不是复制来缓解这种情况。

于 2013-01-21T21:53:00.487 回答