0

I made a simple C++ Chess program, and have been experiencing the aforementioned message from valgrind (added at the end):

I have classes for every piece, they all inherit from an abstract class ChessPiece. The abstract class has a string inside it and an enum. I also have a "Cell" class which knows how to draw itself, and holds a pointer to ChessPiece which holds which piece is currently on it (if it is empty then the pointer is nullptr)

Board class is the class that has all the logic for making moves, checking legality etc. It has a vector of vectors of Cell class (that represents a matrix of cells).

Basically everything apart from the ChessPieces is automatically allocated in memory, and the pieces are allocated using "new" so that they are a part of the heap

I have included below the relevant code (and valgrind report).

ChessPiece Class:

ChessPiece::ChessPiece(string asciiCode, Player player, PieceType piece)
    : _asciiCode(asciiCode), _player(player), _piece(piece)
{

}

ChessPiece::ChessPiece()
    :_asciiCode("")
{

}

and also holds several other getter functions

Cell Class:

ChessPiece * _pieceOccupying = nullptr;

Cell::Cell()
    :Cell(0, 0)
{
    setColour();
}

Cell::~Cell()
{
    delete _pieceOccupying;
}

Cell::Cell(int row, int col)
    : _row(row), _col(col), _occupied(false)
{
    setColour(); //sets enum according to row and col
}

Cell::Cell(int row, int col, ChessPiece * occupying)
    : _row(row), _col(col), _pieceOccupying(occupying), _occupied(true)
{
    setColour(); //sets enum according to row and col
}

void Cell::setOccupying(ChessPiece * occupying)
{
    if (occupying == nullptr)
    {
        _occupied = false;
    }
    else 
    {
        _pieceOccupying = occupying;
        _occupied = true;
    }  
}

ChessPiece * Cell::getOccupyingPiece()
{
    if (_occupied) 
    {
        return _pieceOccupying;
    }
    return nullptr;

}

void Cell::setEmptyCell()
{
    _occupied = false;
    _pieceOccupying = nullptr;
}

Board Class:

private vector< vector<Cell> > _board;

Board::Board()
{
    for (int i = 0; i < BOARD_SIZE; i++)
    {
        vector<Cell> row; //create empty row
        for (int j = 0; j < BOARD_SIZE; j++)
        {
            row.push_back((Cell(i, j)));
        }
        _board.push_back(row);
    }

    initPieces();
}

void Board::initPieces()
{
    //Set Pawns
    for (int i = 0; i < BOARD_SIZE; i++)
    {
        _board[1][i].setOccupying(new Pawn(White));
        _board[6][i].setOccupying(new Pawn(Black));
    }

    //Set Rooks
    _board[0][0].setOccupying(new Rook(White));
    _board[0][7].setOccupying(new Rook(White));
    _board[7][7].setOccupying(new Rook(Black));
    _board[7][0].setOccupying(new Rook(Black));

    //Set Knights
    _board[0][1].setOccupying(new Knight(White));
    _board[0][6].setOccupying(new Knight(White));
    _board[7][6].setOccupying(new Knight(Black));
    _board[7][1].setOccupying(new Knight(Black));

    //Set Bishops
    _board[0][2].setOccupying(new Bishop(White));
    _board[0][5].setOccupying(new Bishop(White));
    _board[7][5].setOccupying(new Bishop(Black));
    _board[7][2].setOccupying(new Bishop(Black));

    //Set Queens
    _board[0][3].setOccupying(new Queen(White));
    _board[7][3].setOccupying(new Queen(Black));

    //Set Kings
    _board[0][4].setOccupying(new King(White));
    _board[7][4].setOccupying(new King(Black));
    _whiteKingCell = &_board[0][4];
    _blackKingCell = &_board[7][4];

}

I have deduced that the following function within the Board class is the problematic one, and specifically the problem seems to be with eating another piece (if i run a small chess game without eating another piece and exit, valgrind shows no errors at all):

void Board::actualMove(Cell * srcCell, Cell * destCell, Player playerMoving)
{

    //do actual move
    ChessPiece * destPiece = nullptr;
    bool previousMoved = false;
    destPiece = destCell->getOccupyingPiece();
    destCell->setOccupying(srcCell->getOccupyingPiece());
    destCell->getOccupyingPiece()->setMoved(true);
    srcCell->setEmptyCell();
    delete destPiece;
    destPiece = nullptr;
}

Valgrind says there aren't any memory leaks, but it says there are invalid reads and writes. I can't seem to understand what I'm doing wrong here. The program works OK without any errors at all. Should I create my own destructor for ChessPiece?

Should I do more inside the destructor for Cell?

Here is the detailed Valgrind report. Thank you to anyone who helps

Valgrind Report:

==3526== Invalid write of size 8
==3526==    at 0x403554: ChessPiece::~ChessPiece() (ChessPiece.h:13)
==3526==    by 0x404F43: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==    by 0x401908: std::vector<std::vector<Cell, std::allocator<Cell> >, std::allocator<std::vector<Cell, std::allocator<Cell> > > >::~vector() (stl_vector.h:415)
==3526==  Address 0x5a1fda0 is 0 bytes inside a block of size 32 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x404F4B: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==    by 0x401908: std::vector<std::vector<Cell, std::allocator<Cell> >, std::allocator<std::vector<Cell, std::allocator<Cell> > > >::~vector() (stl_vector.h:415)
==3526== 
==3526== Invalid read of size 8
==3526==    at 0x4EF14C0: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x40356A: ChessPiece::~ChessPiece() (ChessPiece.h:13)
==3526==    by 0x404F43: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==  Address 0x5a1fda8 is 8 bytes inside a block of size 32 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x404F4B: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==    by 0x401908: std::vector<std::vector<Cell, std::allocator<Cell> >, std::allocator<std::vector<Cell, std::allocator<Cell> > > >::~vector() (stl_vector.h:415)
==3526== 
==3526== Invalid free() / delete / delete[] / realloc()
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x404F4B: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==    by 0x401908: std::vector<std::vector<Cell, std::allocator<Cell> >, std::allocator<std::vector<Cell, std::allocator<Cell> > > >::~vector() (stl_vector.h:415)
==3526==  Address 0x5a1fda0 is 0 bytes inside a block of size 32 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x404F4B: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526==    by 0x4019C6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*, std::allocator<std::vector<Cell, std::allocator<Cell> > >&) (stl_construct.h:151)
==3526==    by 0x401908: std::vector<std::vector<Cell, std::allocator<Cell> >, std::allocator<std::vector<Cell, std::allocator<Cell> > > >::~vector() (stl_vector.h:415)
==3526== 
==3526== Invalid read of size 4
==3526==    at 0x4E92655: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x538D148: __run_exit_handlers (exit.c:82)
==3526==    by 0x538D194: exit (exit.c:104)
==3526==    by 0x5372ECB: (below main) (libc-start.c:321)
==3526==  Address 0x5a1d0b0 is 16 bytes inside a block of size 28 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x40356A: ChessPiece::~ChessPiece() (ChessPiece.h:13)
==3526==    by 0x404F43: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526== 
==3526== Invalid write of size 4
==3526==    at 0x4E9265B: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x538D148: __run_exit_handlers (exit.c:82)
==3526==    by 0x538D194: exit (exit.c:104)
==3526==    by 0x5372ECB: (below main) (libc-start.c:321)
==3526==  Address 0x5a1d0b0 is 16 bytes inside a block of size 28 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x40356A: ChessPiece::~ChessPiece() (ChessPiece.h:13)
==3526==    by 0x404F43: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526== 
==3526== Invalid free() / delete / delete[] / realloc()
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x538D148: __run_exit_handlers (exit.c:82)
==3526==    by 0x538D194: exit (exit.c:104)
==3526==    by 0x5372ECB: (below main) (libc-start.c:321)
==3526==  Address 0x5a1d0a0 is 0 bytes inside a block of size 28 free'd
==3526==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3526==    by 0x4EF14DE: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==3526==    by 0x40356A: ChessPiece::~ChessPiece() (ChessPiece.h:13)
==3526==    by 0x404F43: Cell::~Cell() (Cell.cpp:14)
==3526==    by 0x401CBC: void std::_Destroy<Cell>(Cell*) (stl_construct.h:93)
==3526==    by 0x401C85: void std::_Destroy_aux<false>::__destroy<Cell*>(Cell*, Cell*) (stl_construct.h:103)
==3526==    by 0x401C30: void std::_Destroy<Cell*>(Cell*, Cell*) (stl_construct.h:126)
==3526==    by 0x401BBC: void std::_Destroy<Cell*, Cell>(Cell*, Cell*, std::allocator<Cell>&) (stl_construct.h:151)
==3526==    by 0x401AFE: std::vector<Cell, std::allocator<Cell> >::~vector() (stl_vector.h:415)
==3526==    by 0x401AC6: void std::_Destroy<std::vector<Cell, std::allocator<Cell> > >(std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:93)
==3526==    by 0x401A8F: void std::_Destroy_aux<false>::__destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:103)
==3526==    by 0x401A3A: void std::_Destroy<std::vector<Cell, std::allocator<Cell> >*>(std::vector<Cell, std::allocator<Cell> >*, std::vector<Cell, std::allocator<Cell> >*) (stl_construct.h:126)
==3526== 
==3526== 
==3526== HEAP SUMMARY:
==3526==     in use at exit: 0 bytes in 0 blocks
==3526==   total heap usage: 292 allocs, 294 frees, 11,462 bytes allocated
==3526== 
==3526== All heap blocks were freed -- no leaks are possible
==3526== 
==3526== For counts of detected and suppressed errors, rerun with: -v
==3526== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
user475680
  • 679
  • 1
  • 9
  • 21

1 Answers1

3

Cell breaks the Rule of Three. It attempts to "own" a raw pointer, deleting its target in its destructor, but isn't correctly copyable, so that two Cell objects will both try to delete the same ChessPiece.

Options are:

  • use a smart pointer (or write a copy constructor and copy-assignment operator to correctly juggle the raw pointer) if the cell is supposed to "own" the piece;
  • don't make the cell try to delete the piece, if it isn't supposed to "own" it;
  • use something like boost::optional, to allow the cell to optionally contain a piece without dynamic allocation.
Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Regarding the second option: Does this means basically removing the destructor from Cell class, and then in the Board's destructor function just go over every cell, retrieve the pointer to the ChessPiece and delete it? – user475680 Jan 13 '15 at 12:47
  • @user475680: It certainly involves removing the destructor. I'd use a less flappy way of managing the ownership than pulling raw pointers out of cells, and get rid of all the raw `new` expressions; perhaps storing them all in a container (like `std::vector>`), giving each cell a pointer to one of those, and making sure that the container outlives the cells. But the first or third option would probably be better. – Mike Seymour Jan 13 '15 at 12:53
  • Thank you! I made some changes as per your instructions and now it works great without any valgrind errors! – user475680 Jan 13 '15 at 14:54