Frage

Ich stehe vor einem seltsamen Problem.Ich habe eine abstrakte übergeordnete Klasse (die eine rein virtuelle test()-Methode implementiert) und ihre untergeordnete Klasse (die die test()-Methode implementiert) geschrieben.

class Parent
{
    public :
        Parent();
        virtual ~Parent() = default;

        virtual bool test() const = 0;
};

class Child : public Parent
{
    public :
        bool test() const;
};

Dann habe ich eine „Grid“-Klasse geschrieben, die ein zweidimensionales Array von Zeigern auf Parent enthalten soll.Das Array wird mithilfe der Vektorbibliothek erstellt:„_cells“ ist ein Breite*Höhe-Vektor von Zeigern auf Parent._cells wird während der Grid-Objektkonstruktion mithilfe der dynamischen Zuordnung gefüllt und im Destruktor freigegeben.Operator() (int a, int b) wird überladen, um das Parent-Objekt nach diesem Muster aufrufen zu können: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();
};

In meiner Hauptfunktion ist g ein erstes 2x2-Gitter, das auf dem Stapel erstellt wird.Dann soll g zerstört und in g ein neues 4x4-Gitter aufgebaut werden.Aber es scheitert völlig:

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

Ich denke, dass das Problem von der dynamischen Zuweisung/Aufhebung der Zuweisung jeder Zelle herrührt, aber ich habe keine Möglichkeit gefunden, es zu lösen.

Hier ist mein vollständiger Code. Es ist mir nicht gelungen, ihn weiter zu vereinfachen.Ich habe mein Bestes gegeben.Entschuldigung.

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

Danke.

War es hilfreich?

Lösung

Der Grid Die Klasse verfügt über keinen Kopierzuweisungsoperator, daher wird stattdessen die vom Compiler standardmäßig generierte Version verwendet.Es ist sehr einfach und erstellt nur eine oberflächliche Kopie der Mitglieder.Das bedeutet, dass die für die erstellten Zeiger vorübergehend Objekt Grid(4, 4) werden kopiert (nur die Zeiger und nicht das, worauf sie zeigen), und wenn das temporäre Objekt zerstört wird, werden auch die Zeiger (im Destruktor für das temporäre Objekt) zerstört.Damit bleibt ein Objekt übrig g mit Zeigern auf den jetzt gelöschten Speicher.

Ich schlage vor, dass Sie darüber lesen die Dreierregel.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top