I am writing a chess game to familiarize myself with the C++ language. I have a Board class which contains a 2D array of pointers to Piece objects. I want to implement Board::operator[] such that the following is possible:

Board b;
Piece *p = b[0][0];

I could just return a row of the array which is stored internally. However, I want to implement this in such a way that the pointer to the Piece cannot be overwritten. For example:

b[0][0].moveTo(0,0); // legal

b[0][0] = new Piece; // not legal
*p = new Piece; // not legal (p is defined in the previous code block)

I believe the best way to do this is to use a wrapper class for the object returned by b[0] which also implements operator[]. The first problem I have with this approach is that since a pointer to an object of the Board class is returned, I cannot declare any of the methods/arguments/return values as const, which seems like bad style. The second problem I have is that I do not know how to prevent the current Piece from being replaced via *p = new Piece . Should I return a reference instead?

Thanks.

vijayan121 commented: refreshing to see someone being concerned about const-correctness +8

Recommended Answers

All 9 Replies

I don't think *p = new Piece should be any concern because it won't affect Board b; at all.

to enforce const-correctness (a good idea), use const as required. eg.

#include <cstddef>

struct Piece ;

struct board
{
   enum { N = 8 } ;

   struct the_row 
   { 
     const Piece* operator[] ( std::size_t j ) const
     { return j<board::N && row!=0 ? row[j] : 0 ; }

     private : 
	 const Piece* const* row ;
	 explicit the_row( const Piece* const* r ) : row(r) {}
         friend class board ;
   } ;

   the_row operator[] ( std::size_t i ) const
   { return the_row( i<board::N ? array[i] : 0 ) ; }

   // ... 
   private: 
     Piece* array[N][N] ;
};

> since a pointer to an object of the Board class is returned, I cannot declare any of the
> methods/arguments/return values as const, which seems like bad style.
why can't you? you should return a const pointer.
then you can (and you should) declare selectors as const.

commented: good post +4

@vijayan121: That would work, but I want to be able to modify the Piece corresponding to board[0][0] .

Board b;
const Piece *p = b[0][0];

p.move(0,0); // not legal

Does this mean that I should forget about const qualifiers for this task?

Here is my code for Board.h:

#ifndef BOARD_H
#define BOARD_H

#include <iostream>
#include "Piece.h"

static const int BOARD_DIM = 8;

namespace ChessGame {

class Piece;

class Board
{
  public:
    class PieceDict
    {
      public:
        explicit PieceDict(Piece* const* p) : rowpcs(p) { };
        Piece* const operator[] (std::size_t i) const 
            { return rowpcs[i]; };
      private:
        Piece* const* rowpcs;
    };
    Board();
    PieceDict operator[] (std::size_t i) const 
        { return PieceDict(pieces[i]); };
  private:
      Piece* pieces[BOARD_DIM][BOARD_DIM];
};

std::ostream& operator<< (std::ostream& os, ChessGame::Board& board);

} // end namespace ChessGame

#endif

I return a Piece* const which (as I understand it) should allow me to modify the Piece object. However, when I try to do so I get a Bus error:

Piece* p = NULL;
p = board[0][0];
cout << *p;
p->move(0,0); // Bus error

Why is this?

Although my last question has not yet been answered, I have another. What is the difference between Piece* const* and Piece** const ?

> ...but I want to be able to modify the Piece...
> Does this mean that I should forget about const qualifiers for this task

yes, return a Piece* ( instead of a const Piece* ).
since you are returning a pointer by value, the const in Piece* const is superfluous.

> I return a Piece* const which should allow me to modify the Piece object.
> However, when I try to do so I get a Bus error:
> p->move(0,0); // Bus error > Why is this?

the most likely reason is that in Piece::move , you are attempting to access an invalid address.
a less likely reason is that (depends on the CPU ) you are trying to access an unaligned address.
http://en.wikipedia.org/wiki/Bus_error

> What is the difference between Piece* const* and Piece** const ? Piece* const* => (modifiable) pointer to a constant pointer to a (modifiable) Piece Piece** const => constant pointer to a (modifiable) pointer to a (modifiable) Piece
what follows the const specifier is a const.

Thanks for the info.

the most likely reason is that in Piece::move , you are attempting to access an invalid address.
a less likely reason is that (depends on the CPU ) you are trying to access an unaligned address.
http://en.wikipedia.org/wiki/Bus_error

The move function is empty: void Pawn::move(int rank, int file) { } . I should mention that Pawn (the type that is returned by board[0][0]) is a subclass of the pure virtual class Piece. I'm not sure how a bus error could occur when calling an empty function.

> I'm not sure how a bus error could occur when calling an empty function.

the bus error occurs before the call to void Pawn::move(int rank, int file) { } Piece::move is virtual, a vtbl lookup is required. the vtbl pointer is invalid for the object.

how are you initializing Board::pieces ?
perhaps, you could post the code for Board::Board();

Ah, I'm an idiot. Some of the entries in Board::pieces were NULL. Thanks for pointing that out.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.