STL vector push_back() 内存双重释放

5

可能是重复问题:
什么是三大法则?

我在下面的程序中遇到了内存双重释放的问题。

调试器显示问题出现在push_back()函数中。

A类:

class A {
    public:
        A(int x);
        int x;
};

A::A(int x) {
    this->x = x;
}

二级地址:

class B {
    public:
        B(int x);
        ~B();
        A* a;
};

B::B(int x) {
    this->a = new A(x);
}

B::~B() {
    delete a;
}

主要功能:

int main() {
    vector<B> vec;

    for(int i = 0; i < 10; i++) {
        vec.push_back(B(i)); <------------ Issue is here
    }

    cout << "adding complete" << endl;

    for(int i = 0; i < 10; i++) {
        cout << "x = " << (vec[i].a)->x << endl;
    }

    return 0;
}

这段代码有什么问题?
编辑:错误“double free or memory corruption”

1
https://dev59.com/eG855IYBdhLWcg3wvXDd - Benjamin Lindley
1
请参阅https://dev59.com/eG855IYBdhLWcg3wvXDd。 - hmjd
3个回答

6
你忘记定义复制构造函数和复制赋值运算符,所以你的包装对象被某些B删除了...然后又在一些B的副本超出范围时再次删除。
在这种情况下,它是你已经确定的行上的B(i)临时对象,以及向量中的实现定义数量的副本。
遵守三法则

4
您的代码问题在于“普通”的C/C++指针没有“所有权”的概念。当一个指针被复制时,两个副本都会“认为”它们拥有数据,导致重复删除。
出于对这一事实的认识,C++标准库的设计者引入了一个unique_ptr<T>类,帮助您解决这样的问题。
其中一个指针副本在传递给push_back的B实例中;另一个指针副本则输入到向量中的实例中。

2
在C++11中,除了使用unique_ptr修复类B之外,您还可以编写vec.emplace_back(i)而不是vec.push_back(B(i))。但这只是一个旁白,即使进行了这种更改,您仍然需要以某种方式修复B - Steve Jessop

2

注意三原则

其他人已经反复强调了,所以我不会再深入讨论。

为了遵循三原则并解决您显然想要实现的用法,尝试以下方法。虽然每个人都绝对正确地管理动态成员所有权,但是您的特定示例可以轻松地避免使用它们完全

A类

class A {
    public:
        A(int x);
        int x;
};

A::A(int x) 
   : x(x)
{
}

班级 B
class B {
    public:
        B(int x);
        A a;
};

B::B(int x) 
    : a(x) 
{
}

Main Program

int main() {
    vector<B> vec;

    for(int i = 0; i < 10; i++) {
        vec.push_back(B(i));
    }

    cout << "adding complete" << endl;

    for(int i = 0; i < 10; i++) {
        cout << "x = " << vec[i].a.x << endl;
    }

    return 0;
}

底线: 除非你有充分的理由,并且它是由包含变量(如智能指针或严格遵守三大法则的类)进行寿命管理,否则不要使用动态分配。

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