Stack Overflow Exception when declaring multidimen

2020-04-12 09:54发布

I'm somewhat new to programming in general and I've run into an issue with declaring 3D and 4D arrays. I have several declarations like this at the start of my main function, but I've narrowed the problem down to these 4:

string  reg_perm_mark_name[64][64][64];
short   reg_perm_mark_node_idex[64][64][64];
short   reg_perm_mark_rot[64][64][64][4];
short   reg_perm_mark_trans[64][64][64][3];

When I run my program with these, I get "System.StackOverflowException" in my executable. I would much prefer a way to allocate them dynamically, The way I have it now was meant to be temporary anyway and I'm not sure how to declare array pointers properly.

The 4 elements I'm using in the 4D array reg_perm_mark_trans, for example, are [node index][region index][marker index][xyz coordinates]. Also there's a total of 35 multidimensional arrays being declared at once. (most of them are 1D and 2D) I'm not sure if that helps.

Can someone show me how to make these 4d arrays work or maybe how to make them dynamically allocating with pointers or vectors? Be descriptive please, I'm still learning.

3条回答
Anthone
2楼-- · 2020-04-12 10:14

This line:

string  reg_perm_mark_name[64][64][64]

declares 64*64*64 = 262144 strings on the stack. A std::string is typically about 32 bytes so thats about 8MB. The maximum stack size is typically about 1MB.

To declare the array dynamically you could use std::vector. Generally, multidimensional std::vectors can be a bit cumbersome and it is often better to declare a single dimensional vector and convert to a single index when you access an element:

std::vector<std::string> reg_perm_mark_name(64*64*64);

int i = 13;
int j = 27;
int k = 7;
reg_perm_mark_name[i + 64*j + 64*64*k] = "Hello world!";

But in this case you can declare a multi-dimensional std::vector quite efficiently by using std::array instead of std::vector for the inner types. The use of std::array avoids too many memory allocations as they have a fixed size. I would use typedefs or using aliases to make the declaration clearer:

using StrArray = std::array<std::string, 64>;
using StrArray2D = std::array<StrArray, 64>;

std::vector<StrArray2D> reg_perm_mark_name(64);

reg_perm_mark_name[3][4][7] = "Hello world!";
查看更多
兄弟一词,经得起流年.
3楼-- · 2020-04-12 10:18

Assuming for simplicity that sizeof(string) == 2 (it's probably more), you're trying to allocate (64^3)*9*2 bytes on the stack. That comes out to 4,718,592 bytes, or approximately 4.5 MiB. Most likely, you just don't have 4.5 MiB available on your stack.

Since these variables are declared in main(), you have two possible solutions:

  1. Declare them static.

  2. Declare them outside main(), as global variables.

This will cause them to be allocated before the program starts, rather than on the stack. The only difference between the two approaches is whether they'll be visible in other functions.

There may also be a way to tell your compiler that the program needs more stack space, but I think making them static is probably the better solution here. If they were in a function other than main() though, you'd probably need to do something else.

查看更多
干净又极端
4楼-- · 2020-04-12 10:29

A simple solution is to use static allocation (i.e. move your arrays outside of any function, or mark them as static).

Note that if you use C++ arrays then the usage and footprint are the same but then they behave like proper containers:

array<array<array<string,64>,64>,64> reg_perm_mark_name;

To use dynamic allocation unsafely, you could write:

auto reg_perm_mark_rot = new short[64][64][64][4];
// ...
delete[] reg_perm_mark_rot;

To use it safely, since C++14 (note that the innermost dimension gets special treatment):

auto reg_perm_mark_rot = std::make_unique<short[][64][64][4]>(64);

Of course you can use array instead of C-style arrays with the dynamic options, but then you would have an extra level of indirection to use the array.

查看更多
登录 后发表回答