Declaring 3D array structure in c++ using vector

北城以北 提交于 2021-01-29 07:37:29

问题


Hi I am a graduate student studying scientific computing using c++. Some of our research focus on speed of an algorithm, therefore it is important to construct array structure that is fast enough.

I've seen two ways of constructing 3D Arrays. First one is to use vector liblary.

vector<vector<vector<double>>> a (isize,vector<double>(jsize,vector<double>(ksize,0)))

This gives 3D array structure of size isize x jsize x ksize.

The other one is to construct a structure containing 1d array of size isize* jsize * ksize using

new double[isize*jsize*ksize]. To access the specific location of (i,j,k) easily, operator overloading is necessary(am I right?).

And from what I have experienced, first one is much faster since it can access to location (i,j,k) easily while latter one has to compute location and return the value. But I have seen some people preferring latter one over the first one. Why do they prefer the latter setting? and is there any disadvantage of using the first one?

Thanks in adavance.


回答1:


Main difference between those will be the layout:

vector<vector<vector<T>>>

This will get you a 1D array of vector<vector<T>>.
Each item will be a 1D array of vector<T>.
And each item of those 1D array will be a 1D array of T.

The point is, vector itself does not store its content. It manages a chunk of memory, and stores the content there. This has a number of bad consequences:

  1. For a matrix of dimension X·Y·Z, you will end up allocating 1 + X + X·Y memory chunks. That's horribly slow, and will trash the heap. Imagine: a cube matrix of size 20 would trigger 421 calls to new!
  2. To access a cell, you have 3 levels of indirection:
    • You must access the vector<vector<vector<T>>> object to get pointer to top-level memory chunk.
    • You must then access the vector<vector<T>> object to get pointer to second-level memory chunk.
    • You must then access the vector<T> object to get pointer to the leaf memory chunk.
    • Only then you can access the T data.
  3. Those memory chunks will be spread around the heap, causing a lot of cache misses and slowing the overall computation.
  4. Should you get it wrong at some point, it is possible to end up with some lines in your matrix having different lengths. After all, they're independent 1-d arrays.

Having a contiguous memory block (like new T[X * Y * Z]) on the other hand gives:

  1. You allocate 1 memory chunk. No heap trashing, O(1).
  2. You only need to access the pointer to the memory chunk, then can go straight for desired element.
  3. All matrix is contiguous in memory, which is cache-friendly.

Those days, a single cache miss means dozens or hundreds lost computing cycles, do not underestimate the cache-friendliness aspect.

By the way, there is a probably better way you didn't mention: using one of the numerous matrix libraries that will handle this for you automatically and provide nice support tools (like SSE-accelerated matrix operations). One such library is Eigen, but there are plenty others.

→ You want to do scientific computing? Let a lib handle the boilerplate and the basics so you can focus on the scientific computing part.




回答2:


In my point of view, there are too much advantages std::vector's have over normal plain arrays.

In short here are some:

  • It is much harder to create memory leaks with std::vector. This point alone is one of the biggest advantages. This has nothing to do with performance, but should be considered all the time.
  • std::vector is part of the STL. This part of C++ is one of the most used one. Thousands of people use the STL and so they get "tested" every day. Over the last years they got optimized so radically, they don't lack any performance anymore. (pls correct me if i see this wrong)
  • Handling with std::vector is easy as 1, 2, 3. No pointer handling no nothing... Just accessing it via methods or with []-operator and more other methods.



回答3:


First of all, the idea that you access (i,j,k) in your vec^3 directly is somewhat flawed. What you have is a structure of pointers where you need to dereference three pointers along the way. Note that I have no idea whether that is faster or slower than computing the position within a one-dimensional array, though. You'd need to test that and it might depend on the size of your data (especially whether it fits in a chunk).

Second, the vector^3 requires pointers and vector sizes, which require more memory. In many cases, this will be irrelevant (as the image grows cubically but the memory difference only quadratically) but if your algoritm is really going to fill out any memory available, that can matter.

Third, the raw array stores everything in consecutive memory, which is good for streaming and can be good for certain algorithms because of quick cache accesses. For example when you add one 3D image to another.

Note that all of this is about hyper-optimization that you might not need. The advantages of vectors that skratchi.at pointed out in his answer are quite strong, and I add the advantage that vectors usually increase readability. If you do not have very good reasons not to use vectors, then use them.

If you should decide for the raw array, in any case, make sure that you wrap it well and keep the class small and simple, in order to counter problems regarding leaks and such.




回答4:


Welcome to SO.

If everything what you have are the two alternatives, then the first one could be better.

Prefer using STL array or vector instead of a C array

You should avoid to use C++ plain arrays since you need to manage yourself the memory allocating/deallocating with new/delete and other boilerplate code like keep track of the size/check bounds. In clearly words "C arrays are less safe, and have no advantages over array and vector."

However, there are some important drawbacks in the first alternative. Something I would like to highlight is that:

std::vector<std::vector<std::vector<T>>>

is not a 3-d matrix. In a matrix, all the rows must have the same size. On the other hand, in a "vector of vectors" there is no guarantee that all the nested vectors have the same length. The reason is that a vector is a linear 1-D structure as pointed out in the @spectras answer. Hence, to avoid all sort of bad or unexpected behaviours, you must to include guards in your code to obtain the rectangular invariant guaranteed.

Luckily, the first alternative is not the only one you may have in hands.

For example, you can replace the c-style array by a std::array:

const int n = i_size * j_size * k_size;

std::array<int, n> myFlattenMatrix;

or use std::vector in case your matrix dimensions can change.

Accessing element by its 3 coordinates

Regarding your question

To access the specific location of (i,j,k) easily, operator overloading is necessary(am I right?).

Not exactly. Since there isn't a 3-parameter operator for neither std::vector nor array, you can't overload it. But you can create a template class or function to wrap it for you. In any case you will must to deference the 3 vectors or calculate the flatten index of the element in the linear storage.

Considering do not use a third part matrix library like Eigen for your experiments

You aren't coding it for production but for research purposes instead. Particularly, your research is exactly regarding the performance of algorithms. In that case, I prefer do not recommend to use a third part library, like Eigen, absolutely. Of course it depends a lot of what kind of "speed of an algorithm" metrics are you willing to gather, but Eigen, for instance, will do a lot of things under the hood (like vectorization) which will have a tremendous influence on your experiments. Since it will be hard for you to control those unseen optimizations, these library's features may lead you to wrong conclusions about your algorithms.

Algorithm's performance and big-o notation

Usually, the performance of algorithms are analysed by using the big-O approach where factors like the actual time spent, hardware speed or programming language traits aren't taken in account. The book "Data Structures and Algorithms in C++" by Adam Drozdek can provide more details about it.



来源:https://stackoverflow.com/questions/54883795/declaring-3d-array-structure-in-c-using-vector

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!