サブクラス メソッドを呼び出すとセグメンテーション フォールトが発生する [重複]

StackOverflow https://stackoverflow.com//questions/22014410

質問

奇妙な問題に直面しています。私は、親抽象クラス (純粋な仮想 test() メソッドを実装) とその子クラス (test() メソッドを実装) を作成しました。

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

        virtual bool test() const = 0;
};

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

次に、Parent へのポインターの 2 次元配列を含むことになる「Grid」クラスを作成しました。配列はベクトル ライブラリを使用して行われます。「_cells」は、親へのポインターの幅*高さのベクトルです。_cells は、動的割り当てを使用して Grid オブジェクトの構築中に埋められ、デストラクターで解放されます。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 削除されたメモリへのポインタ付き。

について読むことをお勧めします 3つのルール.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top