-4

I have a piece of code that declares a 3D array of floats that inconsistently compiles.

void ImageCombine()
{

  float *doseArrayTotal = new float[2350][2350][2350];
  float *doseArray1 = new float[1175][1175][1175];
  // I have commented out the rest of my code whilst debugging.
}

If doseArray1 is given dimensions [2350][2350][2350] or [1024][1024][1024], it will compile. Given the dimensions above [1175][1175][1175] or [1000][1000][1000] it will produce the error.

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

The way I am running this code is through a piece of software called root (terrible name) developed by CERN, and the input I provide to run this function is.

[co@fastpc11 mysim]$ root
root [0] .L ImageCombine.C
root [1] ImageCombine()

Any advice as to why my code wont run, and how I might be able to solve this would be greatly appreciated.

Cheers Chris

pseyfert
  • 3,263
  • 3
  • 21
  • 47
Chris
  • 17
  • 5
  • 1
    You are trying to allocate too much continguous memory, your machine does not have enough heap space. That is why when you reduce the array dimensions it works. You'll need to consider a workaround such as a smaller storage scheme. – Cory Kramer Aug 23 '16 at 14:41
  • 1
    if you already handle `float` arrays as float pointers, shouldn't the type be `float***`? – Marcus Müller Aug 23 '16 at 14:41
  • @CoryKramer notice it works with larger sizes, but not with smalelr – Marcus Müller Aug 23 '16 at 14:41
  • @MarcusMüller Most likely the first one succeeds but not the second. Its not a question of size of each, but both of them together. The first alloc alone seems like its 13GB? – Borgleader Aug 23 '16 at 14:42
  • 1
    The reason it "inconsistently" throws this exception is that depending on the code path to get to this line, the heap may have various memory already allocated and/or deallocated, which may or may not leave you enough *contiguous* memory for your array. – Cory Kramer Aug 23 '16 at 14:43
  • 7
    The code is illegal C++. Try compiling it with a real C++ compiler. IIRC ROOT allows complete garbage to be loaded, then falls over at runtime. – juanchopanza Aug 23 '16 at 14:43
  • @CoryKramer as Marcus says I am not short of memory on the machine, it works for some larger arrays. – Chris Aug 23 '16 at 14:43
  • 1
    What @juanchopanza said. How should a single `float*` contain info on three dimensions? Chris, if you just want 2350³ floats in memory, just go ahead and `new float[2350*2350*2350]` and address that. – Marcus Müller Aug 23 '16 at 14:44
  • Possible duplicate of [How do I declare a 2d array in C++ using new?](http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new) – Marcus Müller Aug 23 '16 at 14:45
  • @juanchopanza it is possible that the compiler I'm using is the problem, unfortunately most data analysis in my field is done using this software. If I can determine that there is a bug in the software then I'll move away from it, I'm just trying to determine if I've done something obvious wrong first. – Chris Aug 23 '16 at 14:46
  • @Chris Write real code, and use a real compiler. You can do that *and* use ROOT libraries. – juanchopanza Aug 23 '16 at 14:48
  • It's very likely that you **do not** want to have an arrays of arrays (which is what `float[][]` does) because that is just an ugly redirection into potentially fragmented memory. I'd very strongly recommend you allocate a 1D array, and address that linearly (e.g. `array[x*2350*2350+y*2350+z]`) – Marcus Müller Aug 23 '16 at 14:48
  • 1
    @Chris How can the compiler know in advance, if you're out of runtime resources when executing your program? – πάντα ῥεῖ Aug 23 '16 at 14:48
  • @πάνταῥεῖ tbh, it could check whether max_size_t >= 2350³, but that's pretty much the only thing. – Marcus Müller Aug 23 '16 at 14:49
  • @πάνταῥεῖ it can consistently be run with the larger arrays but consistently not run with certain smaller ones. The memory on the machine used is also massive. Marcus it's mostly because I'm reading in a 3D image so the xyz pixel being addressed from the array the same way makes the code more readable. I've also tried declaring it as float*** as suggested but the problem is identical. – Chris Aug 23 '16 at 14:50
  • Good Lord, why can't people just use `std::array`, or a matrix, it is SOOO much more easier and convenient – Arnav Borborah Aug 23 '16 at 14:51
  • @Chris That doesn't mean you have all that massive memory available for your program. It's OS dependent. – πάντα ῥεῖ Aug 23 '16 at 14:51
  • @MarcusMüller The layout of an array of arrays is the same as that or a single array. There are no extra fragmentation issues. – juanchopanza Aug 23 '16 at 14:52
  • 2
    @ArnavBorborah An array at the stack would make it worse, to no difference. – πάντα ῥεῖ Aug 23 '16 at 14:52
  • @juanchopanza answers of http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new: The way he's doing, no, it isn't. – Marcus Müller Aug 23 '16 at 14:52
  • @MarcusMüller Irrelevant. An array of pointers is not an array of arrays. – juanchopanza Aug 23 '16 at 14:53
  • 2
    "it can consistently be run with the larger arrays but consistently not run with certain smaller ones" Perhaps you should complain to people responsible for ROOT. C++ normally doesn't work this way. Your program is lot legal C++ anyway so I don't see how it can be fixed at the C++ side, other than making it legal C++ of course. – n. m. could be an AI Aug 23 '16 at 14:54
  • @πάνταῥεῖ point taken, now that I think about it, its really the size important here. – Arnav Borborah Aug 23 '16 at 14:55
  • Thanks for the help everyone, I'd borrowed that syntax from another piece of code not knowing it wasn't proper c++. The compiler obviously worked around my ignorance but I finally broke it. I've arranged nested vectors of vectors of vectors to hold the variables and now it behaves properly. – Chris Aug 23 '16 at 15:39
  • Can you show us some more code? How are you expecting to use these pointers? – David Schwartz Aug 24 '16 at 10:13
  • @DavidSchwartz I've changed the answer to show its use, is this what you meant? – Chris Aug 24 '16 at 10:28
  • @Chris Well, I more wanted to see the intended use of the original code. In the original code, these are `float*`'s, not `float ***`'s. – David Schwartz Aug 24 '16 at 10:30
  • You should switch to ROOT6 if possible- ROOT5 is a mess with running non-conformant C++ code, and makes no attempt to check anything when code is loaded. If you need to use ROOT5, loading macros with `.L ImageCombine.C+` will attempt to compile the macro into a library, which catches many errors like this. Here it gives an error `cannot convert ‘float (*)[2350][2350]’ to ‘float*’ in initialization` and refuses to compile. – Chris Sep 07 '16 at 21:09

1 Answers1

1

The originally posted code is not valid C++; it just happened to run when interpreted by CERN Root. To dynamically declare a 3D array:

float*** doseArrayTotal = new float**[2350];
for(int i = 0; i < 2350; ++i){
  doseArrayTotal[i] = new float*[2350];
  for(int j = 0; j < 2350; ++j){
    doseArrayTotal[i][j] = new float[2350];
  }
}

To do the same using vectors:

vector<vector<vector<float> > > doseArrayTotal;
doseArrayTotal.resize(2350);
for (int i = 0; i < 2350; ++i) {
  doseArrayTotal[i].resize(2350);
  for (int j = 0; j < 2350; ++j){
    doseArrayTotal[i][j].resize(2350);
  }
}

These two objects now work as 3D matrices or images, and a float can be stored or accessed at the position (1,2,3) for example by:

float ValueEntered = 7.3;
float ValueExtracted;
doseArrayTotal[1][2][3] = ValueEntered;
ValueExtracted = doseArrayTotal[1][2][3];
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Chris
  • 17
  • 5
  • Please edit your original post instead of adding an answer with the improvements. – Kevin Katzke Aug 24 '16 at 10:18
  • @KevinKatzke I've never written on here before, only come here to search for similar problems. It was suggested by another user to post my solution in the answer section, is this not the proper etiquette? – Chris Aug 24 '16 at 10:21
  • I see, so then you should accept your own answer (click the "check" icon) to clarify that that is the solution to your initial ploblem you want to share with the community. – Kevin Katzke Aug 24 '16 at 10:25
  • "You can accept your own answer tomorrow". I will do though, thankyou – Chris Aug 24 '16 at 10:27
  • @Kevin - See the comments to the question (if they are still present). Breaking the vector down into non-contiguous chunks like this solved Chris's problem (it may have some performance penalty, but there's no penalty worse than crashing!), and I said to post that as an answer. This isn't a clarification, it's the change made to solve the problem, and therefore self-answering is the correct thing to do. – Toby Speight Aug 24 '16 at 10:38