崩溃问题 - 使用指针和析构函数的C ++代码设计

时间:2014-07-17 00:04:18

标签: c++ c++11 pointers reference

我对以下代码有疑问,这些代码崩溃了。我在testfunction()中创建一个局部变量,然后将它(变量“y”)推入一个列表。该变量具有对象类型Ball的成员指针“b”。据我所知,这个局部变量“y”在堆栈上,所以它的'析构函数将在testfunction()完​​成后被调用。另外,据我所知,矢量将一个对象“复制”到其列表中。根据我的学习,最好删除析构函数中的指针(如果在其类中存在指针)。因此,在Example的析构函数中有“delete b”。

我遇到的问题是对象y.b在testfunction()完​​成时被销毁。在main()中,我能够看到“name”的值和“b”的地址,但是对象“b”已经被删除了。我想避免这种情况。

我认为设计代码/使用指针与引用等有问题。请指导我正确的方向,我是白痴!

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Ball
{
    public:
        int a;

        Ball()
        {
            a = 0;
        }

        ~Ball()
        {
            cout << "destroyed Ball()" << endl;
        }
};

class Example
{
    public:
        string name;
        Ball* b;

        Example()
        {
            name = "";
            b = NULL;
        }

        ~Example()
        {
            cout << "destroying Example()" << endl; 
            delete b;
        }
};

void testfunction(vector<Example>& list)
{
    cout << "entered testfunction1()" << endl;

    Example y;
    y.name = "myName";
    y.b = new Ball();
    y.b->a = 5;

    cout << "y.b->a = " << y.b->a << endl;
    list.push_back(y);

    cout << "exit testfunction1()" << endl;
}

void testfunction2()
{
    cout << "entered testfunction2()" << endl;
    Example* y = new Example();
    cout << "exit testfunction2()" << endl;
}

int main() {
    vector<Example> list;
    testfunction(list);
    //testfunction2();

    if(list[0].b == NULL)
        cout << "b is null" << endl;
    else
        cout << "b is not null" << endl;

    cout << list[0].name << endl;
    cout << list[0].b << endl;
    cout << "list[0].b->a = " << list[0].b->a << endl;
    return 0;
}

2 个答案:

答案 0 :(得分:2)

由于class Example具有指针成员并且它尝试拥有动态分配的资源,因此它需要非默认的复制操作,换句话说,它需要用户定义的复制构造函数和赋值运算符。

testfunction内,当您将y复制到vector时,本地yy copied to the vector都指向同一个Ball对象。本地y在函数末尾被销毁,Ball被删除。但是,Ball

仍然指出已删除的y in vector
void testfunction(vector<Example>& list)
{
    // ...

    Example y;
    y.name = "myName";
    y.b = new Ball();
    y.b->a = 5;

    list.push_back(y);

    // ...
} // <-- destructor for Example y is called and y.b is deleted

答案 1 :(得分:1)

为您的班级Example定义复制构造函数和assignement运算符。 这些应该在向量上推回时正确复制您的对象(创建一个重复的Ball对象)。

Example(const Example& a)  
{
    name = a.name;  // attention no dynamic allocation
    cout << "copy" <<endl; 
    if (a.b) {
        b = new Ball(*a.b);   // create a new duplicated Ball 
    }
    else b = NULL; 
}

您的示例中的问题是,在您回滚对象时会调用默认的复制构造函数。它以成员方式复制,因此复制了指向Ball的指针,而不是指向的对象。

另一种替代方法可能是将Ball*替换为shared_ptr<Ball>(相应地,new Ball替换为make_shared<Ball>(),将delete b替换为b.reset() {1}})。原理是这个智能指针跟踪对象指向的时间,因此它不会删除它两次,但只有当它不再在任何地方使用时。