【问题标题】:Is there a way to make a dynamic two-dimensional array in C++?有没有办法在 C++ 中制作动态二维数组?
【发布时间】:2021-06-03 13:04:33
【问题描述】:

所以我想创建一个方形世界的游戏。

开始游戏时,用户应该能够指定世界的大小。

世界被保存为一个二维的短裤数组。

const short gameSize = 4;
short world[gameSize][gameSize];

short gameSize必须是const,否则我不能把gameSize作为world[][]的大小。

但是,这不允许我将 gameSize 设置为玩家希望的大小。

我想到了一些简单的事情,比如

short gameSize = 0;
cout << "World size?" << endl;
cin >> gameSize;
short world[gameSize][gameSize];

如上所述,这是行不通的。

在游戏中,以后无法更改 gameSize 的值。

我怎样才能做到这一点?

【问题讨论】:

  • 这能回答你的问题吗? How to create a dynamic array of integers
  • 这能回答你的问题吗? How do I declare a 2d array in C++ using new?
  • @Edex,虽然链接的问题在技术上是您问题的正确答案,但几乎可以肯定这不是您在特定情况下想要做的。
  • @yaodav 这个问题的几乎所有答案都糟糕。这是一个非常糟糕的规范副本。事实上,这个问题可能应该从轨道上解决。
  • @Frank 原来的问题确实很好,作为一个理论上的 C++ 语言问题。该问题的问题在于,基于其观点和活动,它已成为各种问题的规范链接目标,这是非常有害的。

标签: c++ multidimensional-array


【解决方案1】:
  1. 不要使用new,因为链接的问题/答案会引导您这样做。在您的情况下这是不必要的,并且会无缘无故地增加潜在错误的风险。
  2. 使用std::vector&lt;short&gt; 管理存储世界值的可索引内存块。
  3. 根据需要将二维坐标转换为索引。
  4. (可选)将其全部封装在一个类中,使其隐藏
#include <vector>
#include <cassert>
#include <iostream>

class GameWorld {
  std::size_t world_size_;
  std::vector<short> data_;

public:
  GameWorld(std::size_t size) 
    : world_size_(size) 
    , data_(size * size) {}

  short& operator()(std::size_t x, std::size_t y) {
    assert(x < world_size_ && y < world_size_);

    return _data[y + x * world_size_];
  }

  const short& operator()(std::size_t x, std::size_t y) const {
    assert(x < world_size_ && y < world_size_);

    return _data[y + x * world_size_];
  }
};


int main() {
  short gameSize = 0;
  std::cout << "World size?" << std::endl;
  std::cin >> gameSize;
  GameWorld world(gameSize);

  // Set the value of [0, 0] to 4
  world(0, 0) = 4;
}

这里发生了一些事情:

  1. 使用vector&lt;short&gt; 将为您提供动态大小以及内存安全性。即,事情将在适当的时候“自动”清理。
  2. 您可能很想使用vector&lt;vector&lt;short&gt;&gt;,以便world[x][y]“正常工作”。但这并不是很好,因为内存会到处都是,将其紧密地打包成一维数组会给您带来一系列性能优势总体而言
  3. 您可能“认为”调用函数并对索引进行数学运算很昂贵,但这实际上与您在之前的代码中调用 world[x][y] 时编译器所做的完全相同,因此这里不会产生额外的成本。
  4. assert()s 在调试模式下构建时会发现潜在的错误,并在发布/NDEBUG 模式下完全消失。所以你有一个额外的“免费”安全网。

奖励:如果您想开始涉足模板编程,这是一个很好的学习起点。将GameWorld 模板化,使其可以成为floatint 或某些struct Cell 的世界,而不是始终成为short 的世界,这是有用的、易于操作的,并且不会对其余部分造成干扰代码。

【讨论】:

  • Re (1): OP 没有提到new。非常不幸的是,选择的副本确实如此。
  • @KonradRudolph 该问题被标记为与new 特定的内容重复。我觉得在 OP 的情况下指定这是一个坏主意是有道理的。所以我用第 1 步更新了答案。
  • 在您的回答中,您写道:"packing it tightly into a one-dimensional array gives you a bunch of performance benefits" -- 这主要会在连续访问一个维度时提高性能,但在连续访问另一个维度时不会那么多。因此,Factorio 游戏改为将游戏世界划分为 32*32 块(共 1024 个块)的“块”,每个块连续存储在内存中,这样 CPU 缓存性能对两个维度都有好处。
  • @Lundin 就个人而言,虽然你在技术上是正确的,但我认为过度关注一个显然意味着永远分配一次的课程的分配成本是抓住了一根稻草,尤其是当你的替代方案时在堆栈上使用时仅适用于“小”分配。删除的间接好处更加真实。
  • @Frank 好点。我自己的尝试是查看循环的代码生成,在这种情况下的代码生成是相同的,因为循环内的访问器是内联的,因此不需要添加间接(除了一次,在一开始)。
猜你喜欢
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多