-2

I am trying to do something like this:

std::string* Plane = new std::string[15][60];

However this code seems not to compile. Is there any other way to accomplish the same result? Thanks for any potential help.

trincot
  • 317,000
  • 35
  • 244
  • 286

2 Answers2

1

When using new[] to allocate a multi-dimensional array, you have to allocate each dimension separately, eg:

std::string** Plane = new std::string*[15];
for(int i = 0; i < 15; ++i)
    Plane[i] = new std::string[60];

...

for(int i = 0; i < 15; ++i)
    delete[] Plane[i];
delete[] Plane;

To access a string at a given row/column pair, you can using Planes[row][column] syntax.

Otherwise, flatten it into a 1-dimensional array instead:

std::string* Plane = new std::string[15*60];
...
delete[] Plane;

To access a string at a given row/column pair, you can using Planes[(row*60)+column] syntax.

That being said, you should stay away from using raw pointers like this. Use std::vector or std::array instead:

typedef std::vector<std::string> string_vec;
// or, in C++11 and later:
// using string_vec = std::vector<std::string>;
std::vector<string_vec> Planes(15, string_vec(60));

// C++11 and later only...
std::vector<std::array<std::string, 60>> Planes(15);

// C++11 and later only...
using Plane_60 = std::array<std::string, 60>;
std::unique_ptr<Plane_60[]> Planes(new Plane_60[15]);

// C++14 and later only..
using Plane_60 = std::array<std::string, 60>;
std::unique_ptr<Plane_60[]> Planes = std::make_unique<Plane_60[]>(15);

Any of these will let you access strings using Planes[row][column] syntax, while managing the array memory for you.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Many thanks for your help! Have a nice day! – Heinz Muller Sep 26 '17 at 20:09
  • Just for sake of completeness: `std::string(*planes)[60]` or `std::string(*planes)[15][60]` works, too (and one could use `new std::string[15][16]` instead of the loop again). Sure, that's (if at all) nice only together with an appropriate typedef... And I'm yet missing the `new std::array, 15>()` approach (although one should mention the ugly part that the dimensions are inverted - but that happens with the make_unique, too...). – Aconcagua Sep 27 '17 at 09:27
  • `new std::string[15][60]` is not valid syntax and does not compile, as noted in the OP's question. And the point of my answer was to avoid using `new[]` at all (except in the case where `std::make_unique()` is not available). – Remy Lebeau Sep 27 '17 at 19:09
1

There's three ways of doing this.

The first is to allocate it as an 'array of arrays' structure (I'm converting your code to std::vector, because it's way safer than dealing with raw pointers). This is ideal if you need each row to have its own length, but eats up extra memory:

std::vector<std::vector<std::string>> Plane(15);
for(size_t index = 0; index < 15; index++)
    Plane[index].resize(60);

for(size_t i = 0; i < 15; i++)
    for(size_t j = 0; j < 60; j++)
        Plane[i][j] = "This is a String!";

The second is to allocate it as a flat structure, which dramatically improves performance at the cost of reduction of flexibility:

std::vector<std::string> Plane(15 * 60);

for(size_t i = 0; i < 15; i++)
    for(size_t j = 0; j < 60; j++)
        Plane[i* 60 + j] = "This is a String!";

The third, which I consider the best option by far because of its extensibility, is to roll a Matrix class which abstracts away these details for you, making it less likely you'll make a mistake in your coding:

template<typename T>
class Matrix {
    std::vector<T> _data;
    size_t rows, columns;
public:
    Matrix(size_t rows, size_t columns) : rows(rows), columns(columns), _data(rows * columns) {}

    T & operator()(size_t row, size_t column) {
        return _data[row * columns + column];
    }

    T const& operator()(size_t row, size_t column) const {
        return _data[row * columns + column];
    }
};

Matrix<std::string> Plane(15, 60);
for(size_t i = 0; i < 15; i++)
    for(size_t j = 0; j < 60; j++)
        Plane(i, j) = "This is a String!";

Of course, that's an extremely simplified implementation; you'd probably want to add a bunch of STL-like functionality like rows(), columns(), at(), begin(), end(), etc.

Xirema
  • 19,889
  • 4
  • 32
  • 68
  • Alternative to std::vector (none of the mentioned overhead, still STL container): `std::array` -- probably best used with a typedef... – Aconcagua Sep 26 '17 at 20:24
  • @Aconcagua `std::array` is a good alternative if you don't need dynamic memory, which is implied by the OP's question—they likely would have just written `std::string Plane[15][60];` if stack allocation were a suitable solution. – Xirema Sep 26 '17 at 20:26