简体   繁体   English

对象数组,Java和C ++之间的区别

[英]Array of objects, difference between Java and C++

I am new to C++ and I am porting over a Java project to C++. 我是C ++的新手,我正在将Java项目移植到C ++。

Consider the following Java code, where Piece is a class representing a chess piece: 考虑以下Java代码,其中Piece是表示棋子的类:

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

It creates an array where all the entries are null. 它创建一个数组,其中所有条目都为null。

How can I achieve the same thing in C++? 如何在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++. 编辑:我希望C ++代码高效/优雅,我不关心也不想将粘贴从Java复制到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. 编辑2:代码用于国际象棋程序,数组的大小永远不会改变,性能至关重要。

The simplest way to declare an 8x8 array of optional objects in C++ is like so: 在C ++中声明一个8x8可选对象数组的最简单方法是这样的:

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. boost::optional类型表示一个可选对象(就像Java中的可空引用一样),它没有使用指针类型的所有缺陷。 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<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. 如果您希望能够在运行时调整数组大小,请考虑使用std::vector

As you want it performant, and right for C++ instead of a dumb translation, how about this: 正如你想要的那样,并且正确的C ++而不是愚蠢的翻译,这是怎么回事:

Use a size-1 POD-type for piece. 使用尺寸为1的POD型件。
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 : 或者使用std::array

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

The answer depends, because contrary to Java, in C++ you have different ownership semantics and object lifetime management (the two go hand in hand). 答案取决于,因为与Java相反,在C ++中,您拥有不同的所有权语义和对象生命周期管理(两者齐头并进)。

If you want to model objects similar to java, you would write: 如果你想模拟类似于java的对象,你会写:

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). shared_ptr具有与java对象类似的语义(在任何地方传递它,只要有对它的引用就保证它的生命周期)。

If you want to model observed objects (ie 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. 这确保了当Pieces对象被销毁时,实际的片段本身仍保留在内存中。

If you want to model unique objects, owned by the Pieces array, you should use: 如果要为Pieces数组拥有的唯一对象建模,则应使用:

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. 这确保了当Pieces对象被销毁时,实际的部件本身也会被销毁。

在C ++中你会做类似的事情:

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

Semantically equivalent would be: 语义上等价的将是:

Piece* myPieces[8][8]

as java only knows objects on the heap, pointers. 因为java只知道堆上的对象,指针。

As Piece probably is not a final class, but has King, Queen, this is the way to go. 作为Piece可能不是最后一堂课,但有King,Queen,这是要走的路。

In c++, newly created object (even in array) is created with default constructor. 在c ++中,使用默认构造函数创建新创建的对象(甚至在数组中)。 That's one of the important differences with java. 这是与java的重要区别之一。 If you want to call constructors individually, just use vector of vectors and add each one of them. 如果你想单独调用构造函数,只需使用向量向量并添加它们中的每一个。

I have no experience with java but I believe from what I got that this could be a good replacement in C++: 我没有使用java的经验,但我相信我得到的结果可能是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 std :: array提供与普通C数组相当的性能
  • aggregate initialization provides each pointer a null value 聚合初始化为每个指针提供一个空值
  • fixed size as the java array 固定大小作为java数组

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. 速度对于国际象棋AI来说很重要,所以它可以考虑每秒更多的动作,但你可能需要牺牲优雅。

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. Piece可以是枚举或具有一些有用的getter函数的结构,例如IsWhite。

In C++, you have to declare as: 在C ++中,您必须声明为:

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, 在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++): 由于你已经知道了8x8,你也可以声明为(在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 eg 或根据需要分配,例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM