我面临一个奇怪的问题。我写了一个Parent抽象类(实现了一个纯虚拟测试()方法)和它的Child类(实现测试())。
class Parent
{
public :
Parent();
virtual ~Parent() = default;
virtual bool test() const = 0;
};
class Child : public Parent
{
public :
bool test() const;
};
然后,我编写了一个"Grid"类,该类应该包含指向Parent的指针的二维数组。数组是使用向量库完成的:"_cells"是指向Parent的指针的宽度*高度向量_在使用动态分配构建网格对象的过程中填充单元格,并在析构函数中释放单元格。Operator()(int a,int b)被重载,以便能够使用以下模式调用Parent对象:myGrid(x,y)。
class Grid
{
int _w, _h;
std::vector<Parent*> _cells;
public :
Grid(int w = 0, int h = 0);
~Grid();
Parent* &operator()(int x, int y);
private :
void generate();
};
在我的主函数中,g是在堆栈上创建的第一个2x2网格。然后,它应该摧毁g,并在g中构建一个新的4x4网格。但它完全失败了:
Grid g(2, 2);
std::cout << g(1,1)->test() << std::endl; // Works perfectly
g = Grid(4, 4); // Probably wrong, but don't throw an exception
std::cout << g(1,1)->test() << std::endl; // SIGSEGV
我认为这个问题来自于每个小区的动态分配/脱盐,但我没有找到解决它的方法。
这是我的完整代码,我没有成功地简化它。我尽力了。很抱歉
#include <iostream>
#include <cstdlib>
#include <vector>
class Parent
{
public :
Parent();
virtual ~Parent() = default;
virtual bool test() const = 0;
};
Parent::Parent()
{}
class Child : public Parent
{
public :
bool test() const;
};
bool Child::test() const
{
return true;
}
class Grid
{
int _w, _h;
std::vector<Parent*> _cells;
public :
Grid(int w = 0, int h = 0);
~Grid();
Parent* &operator()(int x, int y);
private :
void generate();
};
Grid::Grid(int w, int h) : _w(w), _h(h), _cells(w*h)
{
generate();
}
Grid::~Grid()
{
for (auto cell : _cells)
delete cell;
}
Parent* &Grid::operator()(int x, int y)
{
return _cells[x*_w+y];
}
void Grid::generate()
{
int cell_num;
for (cell_num = 0; cell_num < static_cast<int>(_cells.size()); cell_num++)
_cells[cell_num] = new Child();
}
int main()
{
Grid g(2, 2);
std::cout << g(1,1)->test() << std::endl;
g = Grid(4, 4);
std::cout << g(1,1)->test() << std::endl;
return 0;
}
谢谢。
Grid
类没有复制赋值运算符,因此将使用编译器默认生成的版本。它非常简单,并且只对成员进行了一次肤浅的复制。这意味着为临时对象Grid(4, 4)
创建的指针被复制(只复制指针,而不是它们指向的对象),当临时对象被销毁时,指针也被复制(在临时对象的析构函数中)。这将留下一个对象g
,该对象具有指向现已删除的内存的指针。
我建议你读一下三条规则。