Вопрос

Я столкнулся со странной проблемой.Я написал абстрактный класс Parent (реализующий чисто виртуальный метод test()) и его дочерний класс (реализующий метод test()).

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

        virtual bool test() const = 0;
};

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

Затем я написал класс Grid, который должен содержать двумерный массив указателей на Parent.Массив создается с использованием векторной библиотеки:«_cells» — это вектор ширины*высоты указателей на родителя._cells заполняется во время создания объекта Grid с использованием динамического выделения и освобождается в деструкторе.Оператор() (int a, int b) перегружен, чтобы иметь возможность вызывать родительский объект, используя этот шаблон:мояСетка (х, у).

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 с указателями на удаленную память.

Предлагаю вам прочитать о правило трёх.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top