简体   繁体   English

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

[英]Crash Issue - C++ Code Design using pointers and destructors

I have a question regarding the following code, which crashes. 我对以下崩溃的代码有疑问。 I am creating a local variable in testfunction() and then pushing it (variable "y") into a list. 我在testfunction()中创建一个局部变量,然后将其(变量“ y”)推送到列表中。 This variable has a member pointer "b" of object type Ball. 该变量具有对象类型为Ball的成员指针“ b”。 As I understand, this local variable "y" is on the stack, so its' destructor will be called after testfunction() is completed. 据我了解,此局部变量“ y”在堆栈上,因此将在testfunction()完​​成后调用其析构函数。 Also, as I understand, a vector "copies" an object into its' list. 而且,据我了解,向量将对象“复制”到其列表中。 From what I've learned, it is best practice to delete a pointer in the destructor if one exists in its' class. 据我了解,最好的方法是在析构函数的类中删除一个指针。 So, there is "delete b" in the destructor of Example. 因此,Example的析构函数中有“ delete b”。

The issue that I am having is that the object yb is being destroyed at the completion of testfunction(). 我遇到的问题是,对象yb在testfunction()完​​成时被破坏了。 In main(), I am able to see the value of "name" and the address of "b", but the object "b" has already been deleted. 在main()中,我可以看到“名称”的值和“ b”的地址,但是对象“ b”已被删除。 I would like to avoid this. 我想避免这种情况。

I think there is an issue with the design of the code/use of pointers vs references, etc. Please guide me in the right direction, I am an idiot! 我认为代码的设计/指针与引用等的使用存在问题。请以正确的方向指导我,我是个白痴!

#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;
}

Since class Example has a pointer member and it tries to own a dynamically allocated resource, it needs non-default copy operations, in other words, it needs user-defined copy constructor and assignment operator. 由于class Example具有指针成员,并且它尝试拥有动态分配的资源,因此它需要非默认的复制操作,换句话说,它需要用户定义的复制构造函数和赋值运算符。

Inside testfunction , when you copy y into vector , both local y and y copied to the vector point to very same Ball object. testfunction内部,将y复制到vector ,将局部yy copied to the vector都指向非常相同的Ball对象。 The local y is destroyed at the end of the function and Ball is deleted. 函数的末尾将销毁局部y并删除Ball However, that deleted Ball still pointed by the y in vector 但是,该删除的Ball仍由y in vectory 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

Define a copy constructor and an assignement operator for your class Example . 为类Example定义一个复制构造函数和一个赋值运算符。 These shall copy properly your object (creating a duplicated Ball object) when pushed back on the vector. 当将它们推回向量时,它们将正确复制您的对象(创建重复的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; 
}

The problem in your example is that the default copy constructor is called when you pushback the object. 您的示例中的问题是,当您推回对象时,将调用默认的副本构造函数。 It copies memberwise and so the pointer to Ball is copied, not the object pointed to. 它以成员方式复制,因此复制了Ball的指针,而不是指向的对象。

Yet another alternative could be to replace your Ball* with shared_ptr<Ball> (and accordingly, new Ball with make_shared<Ball>() and the delete b of the object with a b.reset() ). 还有另一种选择是用shared_ptr<Ball>替换Ball* (因此,用make_shared<Ball>()替换new Ball ,并用b.reset() delete b对象的delete b )。 The principle is that this smart pointer keeps track of the number of time the object pointed to is used, so that it will not delete it twice, but only when its no longer used anywhere. 原理是,此智能指针会跟踪所指向的对象的使用时间,因此它不会删除它两次,而只会在不再在任何地方使用它时才将其删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM