6

I am new to C++ and I am porting over a Java project to C++.

Consider the following Java code, where Piece is a class representing a chess piece:

Piece[][] myPieces = new Piece[8][8];

It creates an array where all the entries are null.

How can I achieve the same thing in C++? I tried:

Piece* myPieces = new Piece[8][8];

But this will create an array with all the entries initialized with the default constructor.

Thanks

Edit: I want the C++ code to be efficient/elegant and I do not care nor wnant to copy paste from Java to C++. I am happy to heavily modify the code structure if needed.

Edit 2: The code is for chess programm, the size of the array will never change and performance is critical.

12
  • 2
    Not a wise thinking if compare two different languages. Commented Sep 24, 2014 at 11:28
  • 2
    Agreed. Don´t try to press Java 1:1 into a different language. Commented Sep 24, 2014 at 11:28
  • 4
    If the comparison to Java bothers you, just think of it as "How can I have a 2D array of optional objects in C++?" I think the answer will sufficiently convince the asker that C++ and Java should be treated in different ways. Commented Sep 24, 2014 at 11:29
  • 1
    In C++, if you want your vector to be 2D, then you need to define it as such. Either use Piece** myPieces = new Piece*[8];, iterate over all 8 elements and create for each a new vector of 8 elements (ergo 64 total elements), or use a 1D vector and use indirect indexing.. Commented Sep 24, 2014 at 11:31
  • 1
    @MarcoA. In Java you do not create an array of objects, you create an array of references. This is the same distinction as for variables. Their values are references but not objects. Commented Sep 24, 2014 at 11:40

9 Answers 9

7

The simplest way to declare an 8x8 array of optional objects in C++ is like so:

boost::optional<Piece> myPieces[8][8];

The boost::optional type represents an optional object (like your nullable references in Java) that doesn't have all the pitfalls of using pointer types. It should be available as part of the standard library in the next few years.

You may prefer to use the std::array type, which is an encapsulation of fixed-size arrays that allows them to be treated as first-class citizens and also provides a nicer interface:

std::array<std::array<boost::optional<Piece>, 8>, 8> myPieces;

If you want to be able to resize your arrays at run-time, consider std::vector instead.

Sign up to request clarification or add additional context in comments.

3 Comments

Java 8 finally has Optional<> too. Nice about array too.
Does boost::optional have any negative impact on performance?
@Romain: Yes, because boost::optional<Piece> is naturally bigger than Piece itself.
5

As you want it performant, and right for C++ instead of a dumb translation, how about this:

Use a size-1 POD-type for piece.
Add all the convenience-methods you might want to it:

struct Piece {
    unsigned char value;
    constexpr Piece() : value() {}
    constexpr operator bool() const {return !value;}
    constexpr bool empty() const {return *this;};
    constexpr bool black() const {return value&0x80;}
    constexpr bool white() const {return value && !black();}
    constexpr unsigned piece() const {return value & 0x7f;}
};

Now that would be an equivalent raw array:

Piece board[8][8];

Or use std::array:

#include <array>
std::array<std::array<Piece, 8>, 8> board;

5 Comments

You are missing const on your methods and I don't understand how the empty function works.
@NeilKirk: Added, also constexpr while I was at it.
Ah, that one is: Convert *this to bool, which means use operator bool.
@Deduplicator Can you explain a bit more about the empty() method? I still don't really understand how it works. Thanks
The empty method is just returning the object itself (*this). Because the return-type is bool, that implies conversion to bool, which means the custom cast is used. That custom operator bool() just returns !value.
3

The answer depends, because contrary to Java, in C++ you have different ownership semantics and object lifetime management (the two go hand in hand).

If you want to model objects similar to java, you would write:

using PiecePtr = std::shared_ptr<Piece>;
std::array<std::array<PiecePtr, 8>, 8> Pieces;

The shared_ptr has similar semantics to a java object (pass it around wherever and it's lifetime is guaranteed as long as there are references to it).

If you want to model observed objects (i.e. the array doesn't own them), you should write:

using PiecePtr = Piece*;
std::array<std::array<PiecePtr, 8>, 8> Pieces;

This ensures that when the Pieces object gets destroyed, the actual pieces themselves remain in memory.

If you want to model unique objects, owned by the Pieces array, you should use:

using PiecePtr = std::unique_ptr<Piece>;
std::array<std::array<PiecePtr, 8>, 8> Pieces;

This ensures that when the Pieces object gets destroyed, the actual pieces themselves get destroyed as well.

5 Comments

Fails on performant and on good C++ for that situation: Polymorphism is severe overkill and not good for performance.
@Deduplicator, what polymorphism? std::array is not polymorphic, neither are std::unique_ptr or std::shared_ptr (I'm not sure what you are refering to).
You are using pointers to Pieces, and there is no reason to use them unless Piece is polymorphic or optional. And considering the OPs constraints on a solution, polymorphism is out and a non-existing Piece should be modeled by a placeholder-Piece.
@Deduplicator, ah, ok. When you mentioned polymorphic I thought "virtual functions" not "pointers". Thanks for explaining.
@utnapistim What is the difference between the 3 cases you explained and: std::array<std::array<Piece, 8>, 8>.
2

In C++ you'd do something like:

std::vector<std::vector<std::unique_ptr<Pieces>>> myPieces;

2 Comments

Fails on "good C++" for that situation, also on "performant".
This is not "the same thing in C++". This is an array of variable length and owned pointers. Java doesn't have owned pointers at all (only shared).
2

Semantically equivalent would be:

Piece* myPieces[8][8]

as java only knows objects on the heap, pointers.

As Piece probably is not a final class, but has King, Queen, this is the way to go.

4 Comments

-1: Nope, it won't compile in C++ (arrays can't have their size not specified). Anyway, this is a poor approach in C++.
@milleniumbug: added 8s; I was more concerned with the type, the pointer, as I think using a pointer is relevant here. What about inheritance? Or do you mean with poor approach using a matrix? Thanks.
Removed -1 since the my main complaint was fixed. However, IMHO this use of inheritance seems forced, since there are only several kinds of chess pieces. (storing different types requires pointer/smart pointer usage and is quite intrusive)
@milleniumbug Yes there is now already an answer with shared_ptr from utnapistim. In fact I was one of the first to use std, so now as Java programmer I love to see Piece* to be deprecated in the C++ community. About inheritance: in java typical used here, but sometimes I dream of an inheritanceless programming language.
1

In c++, newly created object (even in array) is created with default constructor. That's one of the important differences with java. If you want to call constructors individually, just use vector of vectors and add each one of them.

Comments

1

I have no experience with java but I believe from what I got that this could be a good replacement in C++:

std::array<std::array<unique_ptr<foo>, 8>, 8> arr = {};

if(arr[2][3].get() == nullptr) // Can check for null elements
    std::cout << "this is null";

arr[3][4].reset(new foo()); // Initialize an element
  • smart pointer avoids memory leaks
  • std::array provides performances comparable to a normal C array
  • aggregate initialization provides each pointer a null value
  • fixed size as the java array

1 Comment

Yes, and that's probably less ugly to see. Sometimes I'm definitely contrived, sorry :P
1

So you want to make a Chess engine and performance is critical. There are several online tutorials for this. Speed is important for a Chess AI so it can consider more moves per second, but you may need to sacrifice elegance for that.

You can either store the piece values in the board array directly, or store the pieces in a separate backing array and create the board as pointers to these pieces. There are some advantages to the second approach which I can't remember right now.

std::array<std::array<Peice *, 8>, 8> Board;
std::array<Piece, 32> Pieces;

You can represent an empty cell as a null pointer.

If you want everything in the same array, you can simply use

std::array<std::array<Peice, 8>, 8> Board;

But you will need to create a "dummy" piece value to represent an empty cell.

Note there is no dynamic memory allocation and the data is compact in memory so better cache performance.

Piece could be an enum or a struct with some useful getter functions, such as IsWhite.

Comments

0

In C++, you have to declare as:

Piece *** myPieces;

then, allocate as:

myPieces = new Piece **[8];

then,

for (int i = 0; i < 8; i++) {
  myPieces[i] = new Piece *; 
}

Now, if you do,

myPieces[0][0] = new Piece(); // C++, calls default constructor of Piece

In Java,

Piece[][] myPieces; 
myPieces = new Piece[8][8];

now, if you do,

myPieces[0][0] = new Piece(); // Java, calls default constructor of Piece

Since you have 8x8 known already, you may also declare as (in C++):

Piece * myPieces[8][8]; // 64 pointers preallocated as 8 rows, 8 cols

then,

Now, if you do,

for (int i = 0; i < 8; i++) {
  for (int j = 0; j < 8; j++) {
    myPieces[i][j] = new Piece(); // or new Pawn or new Knight etc, subclass of Piece
}}

or allocate as needed e.g.

myPieces[0][0] = new Piece(); // or new Pawn or new Knight etc, subclass of Piece

6 Comments

Why not at least use vectors? Also speed is important and indirect 2d arrays have poor cache performance.
I just answered the question, didn't improve upon, vector usage will provide definite abstraction, but that wouldn't hep to know the difference of Java reference and C++ pointer, So...
This is the way to go, the majority of other answers are just horribly verbose and inefficient. Also, as the OP stated, the board has fixed size so you might consider something like 'Piece *myPieces[8][8]'.
@XDnl Huh?? This is a very verbose and inefficient solution. You even suggest a different and more efficient solution in your same comment.
-1: Horrible, horrible C++ approach. C++'s new is discouraged (exception unsafety, memory leaks, verbosity), and with 41 dynamic allocations, it's also inefficient, since none of the allocations are actually required since the size is known at compile time.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.