4

I was told that in C++, one should always use std::array over c-style array.

After viewing around questions I come across people saying that std::array is better.

In that sense, I used a lot of std::array and sometimes when I use other libraries, I have to use methods that takes in c-style arrays.

For example, I am working with this function

void Draw(float* arg);

Is it possible to pass in std::array<float,4> as a parameter?

Will there be any undefined behavior if I were to pass in &vec4[0] as the parameter?

In that sense, will it be the same for multi-dimensional arrays?

With this array declared as

std::array<std::array<float,4>,4>;

Will there also be any undefined behavior if I were to pass in &mtx4[0][0] as the parameter?

Edit: Thanks for pointing out my error in the code for the multidimensional array. I edited it.

Jack
  • 45
  • 6
  • 4
    `std::array` just has an array as its member. That array acts like any other array. However, consider using `.data()` instead. And your "multidimensional array" example won't even work with a normal array. Don't expect any magic from a 2D `std::array`. – chris Jun 15 '14 at 03:28
  • 2
    _"Is it possible to pass in `std::array` as a parameter?"_ **Yes!** `Draw( my_cpp_array.data() );`. You're asking many questions, so I'm running out of steam. :) – Drew Dormann Jun 15 '14 at 03:28
  • 1
    One nice thing about `std::array` is that if you use the `at()` method to access data, it will do bounds checking, and thus save you from the troubles of the famous of-by-one bug, not always easly detected on raw arrays. http://en.wikipedia.org/wiki/Off-by-one_error – glampert Jun 15 '14 at 03:47
  • 2
    Regarding your last question: absolutely not. You do know that `float[4][4]` is incompatible with `float**`, do you? – n. m. could be an AI Jun 15 '14 at 03:52
  • Thanks for all the prompt replies. I edited the question because I misunderstood the 'multi-dimensional' array earlier. I didn't know about the .data() method. Sorry about asking too many questions. I thought it would be okay considering its about the same thing. =D – Jack Jun 15 '14 at 04:06
  • As-written *now*, yes, you can pass `&mtx[0][0]` to a function requesting a `float*`. Something you *cannot* do is pass `&mtx[0]`, nor `mtx` to a function expecting `float(*arg)[4]`, both of which you *can* do in C were it declared `float mtx[4][4];`. – WhozCraig Jun 15 '14 at 04:14
  • @Jack You have to be careful when selecting answers. The one you selected has a serious error at the moment. – juanchopanza Jun 15 '14 at 08:58
  • Aww man. sorry bout that. So should I unaccept the answer for the moment? Doesn't seem like theres a conclusion yet. Although the comments have already statisfied my initial dilemma. – Jack Jun 16 '14 at 15:14

1 Answers1

0

Is it possible to pass in std::array as a parameter?

Yes. The correct syntax is:

Draw(my_array.data());

Will there be any undefined behavior if I were to pass in &vec4[0] as the parameter?

No. Syntactically it is less good at making your intentions clear, but semantically it is the same.

In that sense, will it be the same for multi-dimensional arrays?

Yes, if you mean classic C multi-dimensional arrays, which are really just flat arrays associated with indexing information. No, if you mean C array-of-array.

float array2d[5][5]; // ok
float *array2d[5]; // not ok
std::array<std::array<float,5>,5> array2d; // not ok

The first has contiguous storage. The other two are arrays of pointer-to-array and have to be handled differently. There is not enough here to recommend how.


I found a reference here to another/new syntax for multi-dimensional arrays. It should provide contiguous storage.

std::array<float,5,5>; // should be ok

I really have no idea what the status of this syntax is. Perhaps others can assist.


After some further investigation of this declaration:

std::array<std::array<float,5>,5> array2d;

The storage for array2d here is all in-line, with no pointers involved. In all the cases I was able to investigate the storage appears to be contiguous, so that the memory layout is the same as for

float array2d[5][5];

This is not a requirement of the standard. A conforming implementation could insert additional information or padding such that sizeof(array<T>) is larger than sizeof(T[]) for some T. If it did then the storage layout for these two would not be the same.

david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • That's a great answer to the later questions, assuming that you are correct. – Drew Dormann Jun 15 '14 at 04:31
  • 1
    @DrewDormann: Thanks, and fair comment. I try to give a good answer to the OP and mostly I get them right, but occasionally a commenter finds an error and I have to edit my answer. The point of SO is that _eventually_ the answers are of high quality, because so many people check them. – david.pfx Jun 15 '14 at 06:00
  • 4
    I am not sure what you mean by your last point, but an `std::array` of `std::array` has contiguous storage. It is like a classic C multi-dimensional array. – juanchopanza Jun 15 '14 at 07:17
  • 3
    @david.pfx: You really need to correct your last point. There's no "array of pointer-to-array" involved with a `std::array` of `std::arrray`. – Blastfurnace Jun 15 '14 at 08:16
  • @juanchopanza: Can you provide a reference to that? I can see nothing helpful in the standard. See my edit. – david.pfx Jun 15 '14 at 08:27
  • It is spread over **23.3.2 Class template array**. The requirements in the layout of a single array are such that an array of arrays is also contiguous memory. An array certainly has no pointers to data, so it is hard to imagine how it could *not* be contiguous. – juanchopanza Jun 15 '14 at 08:32
  • 2
    @david.pfx: §23.3.2.1 [array.overview], "The elements of an array are stored contiguously, meaning that if a is an array then it obeys the identity &a[n] == &a[0] + n for all 0 <= n < N". That requires a `std::array` of `std::array` to be a contiguous array of contiguous arrays. – Blastfurnace Jun 15 '14 at 08:32
  • @Blastfurnace That is not enough though. The same could be said of an `std::vector`. – juanchopanza Jun 15 '14 at 08:57
  • `std::array` is legal, and `.data()` is well behaved, yet `&arr[0]` is undefined. – Yakk - Adam Nevraumont Jun 15 '14 at 09:00
  • @juanchopanza: For me, the ability to do address arithmetic seems to require the same layout as a plain foo[m][n] style array. – Blastfurnace Jun 15 '14 at 09:00
  • @Blastfurnace As I said, the same can be said of vector. But a vector of vectors does not have its elements in a contiguous block of energy. But the following clause mentions that an `std::array` is an *aggregate*, and shows how it can be initialized from an initialization list. I think that pretty much rules out a pointer-to-data implementation. – juanchopanza Jun 15 '14 at 09:02
  • @Blastfurnace: I'm sticking to the view that the storage for array> is not contiguous. A reference that says otherwise would influence my opinion. Meanwhile, this code seems to support my view: https://ideone.com/LUpgnG. Perhaps someone should ask a question...? – david.pfx Jun 15 '14 at 09:08
  • @juanchopanza: You're right, `std::vector` has the same address arithmetic language. I'll let someone more familiar with the standard provide a definitive answer. – Blastfurnace Jun 15 '14 at 09:10
  • @david.pfx: This code seems to support the C-style array-of-array view. http://ideone.com/GYXJWl – Blastfurnace Jun 15 '14 at 09:18
  • @david.pfx: The ideone code you linked is flawed. When you print `pa1` and `pa1+1` you are doing address arithmetic on an `int*` not `std::array` elements. – Blastfurnace Jun 15 '14 at 09:29
  • 1
    @david.pfx Why don't you provide evidence that the storage is *not* contiguous? You won't find it, because there isn't any. – juanchopanza Jun 15 '14 at 09:42
  • @juanchopanza: Can't be done. The standard certainly _permits_ contiguous storage, but the question is whether it is _required_. My view is that the standard permits non-contiguous storage and a complying implementation could have rows of (contiguous) data separated by other stuff. – david.pfx Jun 15 '14 at 10:33
  • 2
    I can't see how that could be implemented while satisfying all the requirements of `std::array`. On the other hand, you are actually making an unsubstantiated assertion. – juanchopanza Jun 15 '14 at 10:35
  • I tried compiling your multi-dimensional std::array and it wouldn't compile. I used the GNU compiler, with the -std=C++11 flag. I also read the article you posted and I am pretty sure that the multi-dimensional array used was one created by the author. – Jack Jun 16 '14 at 16:49
  • @jack: That syntax seems to be a proposal for a future feature, not currently implemented anywhere. – david.pfx Jun 17 '14 at 01:11
  • Your last edit is right, and aligned with what I was trying to get at: my issue is, and always was, with "*The first has contiguous storage. The other two are arrays of pointer-to-array and have to be handled differently*". That bit is wrong. A single array *could* have some data after its elements, but an array of arrays is still a contiguous block. That is not to say it has to consist solely of the elements of its elements. But there is no scope for indirection, so the array of pointers is not a good analogy. Sorry if I wasn't clear about this. – juanchopanza Jun 17 '14 at 05:51
  • @juanchopanza: Thanks. If you look back at my somewhat prophetic first comment, the final answers on SO are good exactly because people like you go to the trouble of making it so. Keep up the good work. – david.pfx Jun 17 '14 at 08:34