1

If we have a class which holds an array, let's call it vector and hold the values in a simple array called data:

class vector
{
public:
   double data[3];
   <...etc..>
};

Note: called as vector is for clearer explanation, it is not std::vector!!!

So my question is that, if I store only typedefs near this array inside the class and some constrexpr, am I correct if the class will be only 3 doubles after each other inside the memory? And then if i create an array of vectors like:

vector vl[3];

Note: size of the array is not always known at compile time, not use 3 for the example.

then in the memory it'll be just 9 doubles after each other, right? so vl[0].data[3] will always return the 2nd vectors 1st element? And in this case is it guaranteed that the result will be always like a simple array in the memory?

I found only cases with array of arrays, but not with array of classes holding an array, and I'm not sure if it is exactly the same at the end. I made some tests and it seems like it is working as I expected, but I don't know if it is always true.. Thank you!

simre
  • 647
  • 3
  • 9

2 Answers2

2

Mostly, yes.

The standard doesn't promise that there never is anything after data in the representation of a vector, but all the implementations that I know of won't add any padding in this case.

What is promised is that there is no padding before data in the representation of vector, because it is a StandardLayout type.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Thanks, so if I need an array of vectors, and element wise operations, it could be better in performance if i create a different class which will allocate a big chunk of memory (ie for 3 vectors, an array of 9 elements), and loop through that one? Since in this case everything is in a big contiguous block of memory without any extra padding for sure? – simre Jun 11 '21 at 10:21
  • @simre it will likely be identical. Having *one* data member (an array is one thing) and nothing `virtual` is laid out with no padding by all the compilers I know of. – Caleth Jun 11 '21 at 10:28
  • @simre As I said in my answer: You can simply `static_assert` the resulting struct size; if it is the sum of all member sizes then there is no padding. In general I'd try to use the natural data representation. If you have three vectors by all means use three `vector`s and not 9 unrelated numbers. – Peter - Reinstate Monica Jun 11 '21 at 10:42
  • @Peter-ReinstateMonica, Yes but it is true only if you know the size at compile time. Sorry, I should have clarified that the size of the array is not always known at compile time. But I see in the link in your answer that the compiler can be "forced" to create a packed struct, so am I correct, if I use int, uint, float, or double for my vector data type, then the compiler won't add padding just put them right one after another? I'm using GCC so I can easily force it based on the linked answer. I try to avoid padding since my arrays can be already pretty big... – simre Jun 11 '21 at 11:04
  • 1
    @simre you can't have a data member with an unknown size in C++. If you want runtime size, use `std::vector` – Caleth Jun 11 '21 at 11:09
  • @Caleth The vector is known, the number of vector is not known. So when the program starts the array size which holds the vectors will be known and fix, but not known at compile time. – simre Jun 11 '21 at 11:11
  • @simre In order to verify that `v` in `vector v[3]` indeed contains 9 adjacent doubles it is sufficient to `static_assert (sizeof(vector) == 3*sizeof(double))`. If that's the case the compiler does not add padding after the array in each `vector`, and between array elements in `v` it is not allowed to. – Peter - Reinstate Monica Jun 11 '21 at 11:13
  • @Peter-ReinstateMonica Ookay I think I see now. So at comiple time I check if the class size is correct, and if it is then I'm happy and all done. I went on the wrong path but now I see what you mean. It is perfect. Thanks! – simre Jun 11 '21 at 11:16
  • @simre still use `std::vector` for dynamicly sized "arrays" `int size = /*something*/; vector vl[size];` is not C++, that should be `std::vector vl(size);` – Caleth Jun 11 '21 at 11:17
  • @Caleth I would like to store in raw arrays. I made some tests before and if I store a bunch of vectors (well, it was a 3*numberOfVectors sized array), or in std::vector, and perform element wise operators, the raw array easily outperformed the std::vector – simre Jun 11 '21 at 11:20
  • @Caleth And this lib will be wrapped in CPython so I would like to squeeze out from C++ as much as possible (well, with my knowledge). I know numpy, etc, but this is mostly a fun project where I try to do everything on myself for practicing and learning. – simre Jun 11 '21 at 11:23
1

You are right with your first example: The class layout is like a C struct. The first member resides at the address of the struct itself, and if it is an array, all the array's members are adjacent.

Between struct members, however, may be padding; so there is no guarantee that the size of a struct is the sum of all member sizes. I'd have to dig into the standard but I assume this includes padding at the end. This answer affirms that; assert(sizeof(vector) == 3*sizeof(double)) may not hold. In reality I'd assume that an implementation may pad a struct containing three chars so that the struct aligns at word boundaries in an array, but not three doubles which are typically the type with the strongest alignment requirements. But there is no guarantee between implementations, architectures and compiler options: Imagine we switch to 128 bit CPUs.

With respect to your second example: The above applies recursively, so the standard gives no guarantee that the 9 doubles will be adjacent. On the other hand, I bet they will be, and the program can assert it with a simple compile-time static_assert.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62