使用析构函数时出现双重释放或损坏问题

8
在下面的代码中,当我添加带箭头的行时会出现错误:

错误:在“./a.out”中双重释放或损坏(fasttop): 0x00000000007a7030 * 中止(核心已转储)

如果不使用析构函数,代码可以正常工作。有什么想法吗?
#include<iostream>
#include<vector>

struct Element
{
    int *vtx;

    ~Element ()
    {
        delete [] vtx;
    }
};

int main ()
{
    Element *elm = new Element [2];
    elm[0].vtx = new int [2]; // <----- adding this gives error

    std::vector <Element> vec;
    vec.push_back (elm[0]);
    vec.push_back (elm[0]);

    return 0;
}

  1. http://klmr.me/slides/modern-cpp/
  2. http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html
  3. http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
- Griwes
2
@juanchopanza,我不确定 - 这是一个问题,"遵循三法则"(或现在的零法则)是答案,而不是关于三法则是什么的问题(因为OP在提问之前没有听说过这个术语)。 - Griwes
这段代码没有好的方法可以工作,除非进行全面改造。最简单的解决方案是将 vtx 改为 std::vector<int> 并且去掉析构函数。即使是复制构造函数也无法帮助你。 - Ryan Haining
@Griwes 在重复的信息中已经回答了这个问题。我只是遵循常见的做法,但如果这样不对,我很乐意取消关闭投票。 - juanchopanza
@juanchopanza,我只是在想,我选择的重复是否比你选择的更正确。 - Griwes
2个回答

5
当你将elm[0]添加到vec中时,vec中存储了elm[0]的副本。由于你没有定义复制构造函数,编译器使用默认构造函数--执行成员变量的逐个复制。在这种情况下,它保留了指针vtx的副本。现在有三个对象指向相同的内存。
vec被销毁时,它会调用两个对象的析构函数。它们各自尝试对相同的指针执行delete操作。因此出现错误。
如果想避免这些错误,请查看三大法则

基本上问题就在于这里进行了浅拷贝。写一个复制构造函数和赋值运算符,并且在你有指针成员时进行深拷贝。 Element(const Element& e) { cout << "复制构造函数\n"; vtx = new int [2]; } - sudheerbb

3
这是因为你在将Element推入向量中时制作了它的副本,但vtx没有被复制,所以在main()结束时,你会有三个指向相同vtx的Element。当程序终止时,它们中的全部三个都会尝试删除相同的int数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接