在c ++中初始化二维对象数组

时间:2016-05-20 00:28:32

标签: c++ arrays

我知道之前曾经问过(或者有些类似的变化)但是我无法让它发挥作用。

我正在尝试创建一个由充满方块的棋盘组成的棋盘游戏。我试图将我的电路板建模为Square对象的二维数组。可以使用任何宽度或高度创建板,并通​​过构造函数传递这些参数。这是我正在使用的代码:

Board.h

#ifndef BOARD_H
#define BOARD_H

#include "Square.h"

class Board{
public:
    Board(int w, int h);

private:
    Square **squares;
    const int width;
    const int height;
};

#endif

Board.cpp

#include "Board.h"

Board::Board(int w, int h):width(w), height(h) {
    squares = new Square*[width];

    for (int i = 0; i < width; i++) {
        squares[i] = new Square[height];
    }
}

然而,当我尝试编译它时,我得到一个错误,似乎表明squares[i] = new Square[height]正试图调用Square对象的默认构造函数(在这种情况下我不想存在也不调用) 。

Board.cpp: In constructor ‘Board::Board(int, int)’:
Board.cpp:7:33: error: no matching function for call to ‘Square::Square()’
   squares[i] = new Square[height];

有什么想法吗?这可能在C ++中吗?

3 个答案:

答案 0 :(得分:4)

您的代码与此相同:

struct Foo
{
    Foo(int){} // no default constructor
    // Foo() = default; /* uncomment this and it will work */
};

int main()
{
    Foo* pFoo = new Foo[10]; // need a default ctor
    delete[] pFoo;
}   

问题是在Foo* pFoo = new Foo[10];的rhs上,您正在分配内存以及创建 10 Foo个对象。编译器不知道如何执行后者(创建对象),因为您没有提供默认构造函数。要使上面的代码按原样运行,您需要为每个对象的非默认ctor指定所有参数,例如:

Foo* pFoo = new Foo[10]{1,2,3,4,5,6,7,8,9,0}; // this will work

更好的选择是使用std::vector代替。如果你想知道为什么后者在没有需要没有默认构造函数的对象的情况下工作,那是因为它使用placement new,并根据需要初始化元素。

Here您可以看到如何使用展示位置new

编辑

代码

Foo* pFoo = new Foo[10]{1,2,3,4,5,6,7,8,9,0}; 

在gcc中编译,但是clang无法编译它(带有-std=c++11标志)。跟进问题here

答案 1 :(得分:2)

你要求它构造一个n平方的缓冲区。它试图这样做,但失败了,因为它无法构建它们。

如果您想要n方块的内存,请使用new std::aligned_storage_t<sizeof(Square),alignof(Square)>[Count]。然后使用placement new依次构造每个元素。

但这是一个愚蠢的想法。它复杂,不透明,容易出错。

简而言之,手动停止管理内存

vector为您解决了这个问题。

创建正方形矢量矢量。或者创建一个平面向量,并进行数学运算以找到索引。它在内部执行对齐的存储位,并使用placement new来按需构建,因此您不必自己编写那些危险的棘手代码。

使用它可以动态高效地增长它们,并且可以很好地替换手动管理的数组。但是你需要将它们从最小元素发展到最大元素。如果您不想这样,请使用唯一ptrs到Square的向量,并根据需要进行分配(如果使用C ++ 17 / 1z编译器,则为std::experimental::optional<Square>。)

或者只使用pair<int,int>Square的地图并使其稀疏。请注意,如果您不想使用Square的默认ctor,您将被激活而不会调用[]。同样,你可以直接使用独特的ptrs而不是Squares。

有很多很多选择。

还要考虑使用默认的Square ctor:常规类型很棒。

答案 2 :(得分:1)

正如另一个提到的答案,你可以创建一个平面向量并做一些简单的算术来计算索引。

int main() {
    // dimensions of the board
    int width = 100;
    int height = 102;

    // some coordinates on the board
    int x = 10;
    int y = 32;

    // allocate memory for every element on the board (10200 elements)
    int * board = new int[width * height];

    // access element (x, y) of the board
    int val = board[y*width + x]

    // don't forget to delete dynamic memory!
    delete [] board;
}

没有两个不同的坐标具有相同的索引。