我对以下代码有疑问,这些代码崩溃了。我在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;
}
答案 0 :(得分:2)
由于class Example
具有指针成员并且它尝试拥有动态分配的资源,因此它需要非默认的复制操作,换句话说,它需要用户定义的复制构造函数和赋值运算符。
在testfunction
内,当您将y
复制到vector
时,本地y
和y 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}})。原理是这个智能指针跟踪对象指向的时间,因此它不会删除它两次,但只有当它不再在任何地方使用时。